Compare commits

...

483 Commits

Author SHA1 Message Date
Björn Petersen 6c625d078f Update CHANGELOG.md 2017-04-14 14:29:47 +02:00
B. Petersen a69afe11f4 Pimp notifications. 2017-04-13 23:55:51 +02:00
B. Petersen 4ff15e433b Use 'white' as default LED-color, show text 'Default' if the default LED-color is selected (instead of a white circle on white background). 2017-04-13 23:03:02 +02:00
B. Petersen 6c81d03c50 Use delta-chat default sound if choosing 'default' in the chat-sound-settings. 2017-04-13 22:37:15 +02:00
B. Petersen 9f0b322249 Remove unsued strings that have no default. 2017-04-13 16:26:41 +02:00
B. Petersen e8831b0dfc Remove bad libEtPan version declaration. 2017-04-13 13:58:53 +02:00
B. Petersen d6e9ba2ea9 Rewording the 'Mute for' options - thanks for the hint, Tobi. 2017-04-13 12:33:41 +02:00
B. Petersen 2c8c5a7558 Adapt copyright note. 2017-04-13 11:05:30 +02:00
B. Petersen d2e76a5e61 Pimp 'Notifications and sounds' dialog. 2017-04-12 23:02:54 +02:00
B. Petersen 2263c24019 Typo 2017-04-12 14:13:35 +02:00
B. Petersen 19e414e65c Update messenger-backend submodule. 2017-04-12 14:11:22 +02:00
B. Petersen f5a52c1aa2 Changelog. 2017-04-12 14:10:09 +02:00
B. Petersen 1cf5039c81 Additional heartbeat call. 2017-04-12 11:36:07 +02:00
B. Petersen 90a5e39872 Personalize needed foreground notification. 2017-04-11 14:44:24 +02:00
B. Petersen 30868b107e Remove dead code. 2017-04-11 12:37:16 +02:00
B. Petersen 546d4a3bda Remove dead code. 2017-04-11 12:23:11 +02:00
B. Petersen 33eaf71e5b Remove currently unused AOSP Volley. 2017-04-11 12:08:15 +02:00
B. Petersen a61e73b91b Improve color selector, selection is still a little bit weird, however, much better. 2017-04-10 22:51:10 +02:00
B. Petersen f03a3a9b50 New background-active-icon. 2017-04-10 21:09:56 +02:00
B. Petersen e2225be331 Installing an permanent foreground service to satisfy Googles battery optimization stuff, hopefully, *REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (which is only possible with the mercy of Google) is no longer needed. 2017-04-10 18:11:52 +02:00
B. Petersen f1f23a5099 Additionally log to a file to fix temporary notification problems. 2017-04-10 13:30:13 +02:00
B. Petersen db3bcb017c Remove void FileLog commands. 2017-04-10 12:39:50 +02:00
B. Petersen ab0ce1393e Remove void FileLog commands. 2017-04-10 12:01:56 +02:00
B. Petersen b941b9e21a Request the user to ignore the battery optimizations which avoid running Delta Chat properly. 2017-04-07 19:36:05 +02:00
B. Petersen b838e0d69e If possible, use Java's Log-class instead of JNI's __android_log_print() which is not available on some devices (eg. LG X Cam). 2017-04-05 16:11:56 +02:00
B. Petersen 8459f5552d Avoid global JNI-namespace pollution. 2017-04-05 14:35:28 +02:00
B. Petersen 293d249024 Changelog. 2017-04-04 22:48:15 +02:00
B. Petersen 38a39aec17 Slight logo update. 2017-04-04 22:17:28 +02:00
B. Petersen f4fb855cb6 Add vertical scrollbar, where appropriate, and use system 'glow' color. 2017-04-04 18:49:24 +02:00
B. Petersen 8fa34e8659 Do not connect if we're not configured (otherwise a 'not connected' error pops up during the first app run). 2017-04-04 17:59:32 +02:00
B. Petersen eb2f2de29c Remove Exoplayer, we prefer the native video player. 2017-03-31 21:23:16 +02:00
B. Petersen 1b2c5a028a Remove dead http-code, still continued. 2017-03-31 20:09:24 +02:00
B. Petersen 4057c08df9 Remove dead http-code, still continued. 2017-03-31 20:05:32 +02:00
B. Petersen 074d2054ec Remove dead http-code, continued. 2017-03-31 19:50:53 +02:00
B. Petersen cf2ea4cc56 Remove dead http-code. 2017-03-31 19:34:49 +02:00
B. Petersen cff6b6bba7 Update Korean. 2017-03-31 12:56:00 +02:00
B. Petersen 595111fb56 Update messenger-backend submodule. 2017-03-31 11:41:53 +02:00
B. Petersen cfc0485579 Changelog. 2017-03-31 11:40:20 +02:00
B. Petersen 7e7d4176f2 Adapt layout. 2017-03-31 11:36:54 +02:00
B. Petersen 8abaa7bc02 Dynamically adapt video bitrate for longer videos to an attachment-size of max. 25 MB. 2017-03-31 01:40:38 +02:00
B. Petersen 714e079b17 Split video-result-calculation from original-value-loading. 2017-03-31 00:38:10 +02:00
B. Petersen 6983491586 Check, if we can really compress videos. 2017-03-31 00:02:30 +02:00
B. Petersen 2cea64ccff Remove unneeded file loader calls. 2017-03-30 23:35:25 +02:00
B. Petersen 0ef81716c5 Use system 'CheckBox' instead of user-defined 'Switch'; the latter is not a perfect choice in a list of settings, see Android GUI guidelines, and did never worked well, eg. moving the switch did never worked as expected. 2017-03-30 21:14:19 +02:00
B. Petersen c780ddf081 Support intents with mailto:-links, show preview before sending a message. 2017-03-30 17:55:43 +02:00
B. Petersen 30b778c4f6 Allow sharing images or documents from other apps to Delta Chat. 2017-03-29 21:50:57 +02:00
B. Petersen 5e0c7553e2 Show error toasts only if the app is in foreground. 2017-03-29 21:19:44 +02:00
B. Petersen b5fe0acd89 Cleanup. 2017-03-29 21:13:15 +02:00
B. Petersen 01551fe71a Cleanup. 2017-03-29 20:35:08 +02:00
B. Petersen edd4176890 Update messenger-backend submodule. 2017-03-28 16:00:23 +02:00
B. Petersen f4f27ac0ae Changelog. 2017-03-28 16:00:04 +02:00
B. Petersen aeb297548c Remove unused variable. 2017-03-28 11:04:52 +02:00
B. Petersen eb3aa46ff7 After the app is paused, show messages the next 10 minutes immediately. Affter that, we sleep most time (11/12th=55 seconds) of a minute. 2017-03-28 10:59:50 +02:00
B. Petersen 05fbf5bdce Add missing file. 2017-03-27 22:17:03 +02:00
B. Petersen 8a5f05fe2e Create an alert that wakes up the app from time to time; if there's stuff to do, the backend acquires a wake loke then. Additionally, if the app is just dismissed, we keep another wakelock for some minutes to catch messages the user just expects in that moment. 2017-03-27 22:16:26 +02:00
B. Petersen 590841d139 Clearer bootup-code naming. 2017-03-24 19:36:16 +01:00
B. Petersen 44caf01cae Cleanup code to load the native library. 2017-03-24 17:11:31 +01:00
B. Petersen db36341251 Cleanup. 2017-03-24 15:43:28 +01:00
B. Petersen 0a63816ece Acquire wakeLock to receive notifications if 'keep-alive' is on. 2017-03-23 22:18:17 +01:00
B. Petersen ceb0155f5f Cleanup keep-alive code. 2017-03-23 21:01:36 +01:00
B. Petersen 723e677b2b Use more general text 'Audio' instead of 'Music' for audio-files with unknown content. 2017-03-23 16:00:11 +01:00
B. Petersen fab24ee956 Update messenger-backend submodule. 2017-03-22 23:26:07 +01:00
B. Petersen 94f4c8b302 Update changelog. 2017-03-22 23:25:50 +01:00
B. Petersen 008a2410a7 Update changelog. 2017-03-22 15:55:46 +01:00
B. Petersen b43f337af9 Show language name in english in language select activity. 2017-03-22 15:49:56 +01:00
Björn Petersen 21895cf00f Merge pull request #59 from aligitor/master
Add Hungarian translation.
2017-03-22 15:31:53 +01:00
aligitor 721d016d86 Create strings.xml
Hungarian translation file.
2017-03-22 12:42:38 +01:00
B. Petersen 89aaa9c072 Show percentage in the configuration progress dialog. 2017-03-22 00:04:27 +01:00
B. Petersen bcb00a9d23 Add IMAP/SMTP security options. 2017-03-20 21:11:59 +01:00
B. Petersen 34cd40fdd9 Support HTML-only messages. 2017-03-18 11:18:35 +01:00
B. Petersen c8001cedce Provide an http/https-get function for the backend. 2017-03-15 22:23:28 +01:00
B. Petersen 880353888b Add input types for the account configuration dialog. 2017-03-15 21:04:10 +01:00
B. Petersen 2c67d20233 Add options for SSL/TLS and STARTTLS. 2017-03-15 16:32:15 +01:00
B. Petersen 42c08a4d5b Test IMAP and SMTP server when calling the configure-function. 2017-03-14 18:25:20 +01:00
B. Petersen 01bf0f3af5 Remove unused notifications. 2017-03-14 11:41:29 +01:00
B. Petersen e765968c2c Language (do not show 'configuring account' message as the may be interpreted as we do something with the server settings). 2017-03-14 11:09:49 +01:00
B. Petersen 3837463e41 Use larger labels for the basic account settings. 2017-03-13 23:37:13 +01:00
B. Petersen 545a2ddc24 Hide advanced account settings by default (in general, we'll try to find them out automatically). 2017-03-13 23:12:56 +01:00
B. Petersen 4f6f0b4685 Cleanup cache settings code. 2017-03-13 19:36:41 +01:00
B. Petersen 1d1bad8b3b Fine-tuning error handling. 2017-03-13 14:00:30 +01:00
B. Petersen af5769f231 Improve error handling. 2017-03-12 21:03:28 +01:00
B. Petersen 42c6337c4d Show popup errors. 2017-03-12 00:33:08 +01:00
B. Petersen 37a49c9d39 Add Korean. 2017-03-11 22:41:45 +01:00
B. Petersen 3b2f778114 Repair 'Default language' option and cleanup some language stuff. 2017-03-11 21:10:31 +01:00
B. Petersen b55cc03f6d Correct string. 2017-03-11 18:31:02 +01:00
B. Petersen 2e6eead045 Change the order of the account input fields. 2017-03-11 18:17:44 +01:00
B. Petersen e77c3303a1 Show versionCode in about dialog. 2017-03-11 11:55:32 +01:00
B. Petersen e83c4f315c Force unique video names in the blob directory. 2017-03-11 11:35:34 +01:00
B. Petersen 833c75d874 Change order of 'new group icons'. 2017-03-11 10:45:47 +01:00
B. Petersen 9688003648 Force video-recoding for videos which size is okay but the bitrate is too high. Correct maximum bitrate handing (was checked too son before and scaled down afterwards, on typical devices, this resulted in a bitrate of about 500 kbit which we use as a maximum now; everyone is welcome to improve all this stuff). 2017-03-10 19:15:54 +01:00
B. Petersen a2609d5bbe Catch video thumbnail creation errors. 2017-03-10 19:11:49 +01:00
B. Petersen 227f129455 Update changelog. 2017-03-10 13:43:32 +01:00
B. Petersen 4e683e5b37 Update messenger-backend submodule. 2017-03-10 13:29:38 +01:00
B. Petersen c5a0a00dd8 In video editor, show resulting length and size in action bar. 2017-03-10 13:25:46 +01:00
B. Petersen de0bce163f Move 'done' button in the group-creation dialog to the very most right position. 2017-03-10 12:05:46 +01:00
B. Petersen 9dcb58c1ea Use SI-prefix for file sizes. 2017-03-10 11:30:33 +01:00
B. Petersen 4729642f87 Show play-button overlay in video preview. 2017-03-10 01:28:58 +01:00
B. Petersen 751cbfa635 Create and use video thumbnails. 2017-03-10 01:17:26 +01:00
B. Petersen e40cae149b Mark some members as being final or remove them. 2017-03-09 21:33:49 +01:00
B. Petersen 758dfbaa67 Remove unneeded FileDidUpload and FileDidFailUpload notifications. 2017-03-09 19:08:48 +01:00
B. Petersen 29ec49b806 Show sended video messages immediately by using the new .increation method (before, video messages are shown after compression is done; this may take several 10th's seconds). 2017-03-09 18:43:07 +01:00
B. Petersen 8afb5595d0 Read bytes from file system, not from database. 2017-03-09 12:25:33 +01:00
B. Petersen 8430e9ddc6 In full-screen-dialogs with okay-checkmarks, we use a cancel-button instead of an ambiguous back-button, see the Material Design Guidelines, https://material.io/guidelines/components/dialogs.html#dialogs-alerts . 2017-03-09 11:44:29 +01:00
B. Petersen 7439fafe2b Name passcode activity screens. 2017-03-09 11:33:51 +01:00
B. Petersen e1655a40bd Start showing MiB already at 999 KiB, this avoids confusion with four digit KiB which may be being already Megabytes ... 2017-03-09 10:00:04 +01:00
B. Petersen 92fc521d5b If we're not playing, a long press on the waveform selects the whole message as usual. 2017-03-09 09:30:49 +01:00
B. Petersen 023d34f2b6 Simplify size formatting.. 2017-03-09 09:15:58 +01:00
B. Petersen 8fc064a5a4 Show videos using the system player, this seems to be more reliable. 2017-03-08 22:04:17 +01:00
B. Petersen b9a329f416 Recode and send videos. 2017-03-08 21:59:39 +01:00
B. Petersen 4997fa7301 Prepare sendMessage() function for async messages (needed for videos which must be recorded first). 2017-03-08 20:51:14 +01:00
B. Petersen e267d67d6e Stop playback if the playing message gets deleted. 2017-03-08 20:48:02 +01:00
B. Petersen 83b04a97ef Recode videos with the same size but different rotation. 2017-03-08 20:44:06 +01:00
B. Petersen 7852c9e9f9 Light video editor layout. 2017-03-08 16:09:54 +01:00
B. Petersen 009adc09bc Removed unneeded image search function, cleanup gallery code. 2017-03-08 13:57:18 +01:00
B. Petersen 4d3929576d Use light gallery theme, use default colors. 2017-03-08 12:23:39 +01:00
B. Petersen 7712def225 Prepare sending videos. 2017-03-08 00:19:28 +01:00
B. Petersen 9509919431 Repeat the normal play/pause buttons in the status-bar-player for internal consistence. 2017-03-07 23:13:26 +01:00
B. Petersen 15cc62f559 Make status-bar-player layout more compatible. 2017-03-07 22:44:26 +01:00
B. Petersen ae46cbbf5e Remove content intent for status-bar-player (unexpected behaviour). 2017-03-07 19:20:00 +01:00
B. Petersen 1664fcdc84 Remove suspicious voice proximity commands. 2017-03-07 19:17:16 +01:00
B. Petersen 2c45f4af37 Allow generating waveforms without a messsage object. 2017-03-07 19:00:14 +01:00
B. Petersen b3d1747c0b Fix a redrawing bug on Kit Kat. 2017-03-07 18:05:40 +01:00
B. Petersen 693952d0eb Show waveform for voice messages. 2017-03-07 17:17:37 +01:00
B. Petersen 0ad5bd6e48 Update some colors and measures. 2017-03-07 14:47:34 +01:00
B. Petersen 89c34f89c9 Remove screenshot observer. We do not want to observe the users of the app; moreover, this is useless and results in false security. 2017-03-07 13:13:20 +01:00
B. Petersen 70971a73ad Remove unused download queues, this stuff goes to the backend, if needed. 2017-03-07 12:39:28 +01:00
B. Petersen 2c5b377712 Check permission on raise-to-speak. 2017-03-07 12:06:35 +01:00
B. Petersen ae4b5a711b Go to previous/next media. 2017-03-06 19:31:52 +01:00
B. Petersen 252bc52d47 Show correct media information from the backend. 2017-03-06 17:11:12 +01:00
B. Petersen 655783db1e Make mrpoortext_t more general-purpose-use. 2017-03-05 16:53:16 +01:00
B. Petersen 10b2af3656 Simplify audio select dialog. 2017-03-05 14:23:31 +01:00
B. Petersen 54c3a963a4 Smarter voice message preview. 2017-03-03 21:32:56 +01:00
B. Petersen a7836eaded Sending voice messages using 'Raise to speak' :-) 2017-03-03 19:20:25 +01:00
B. Petersen 10fcbdc81d Bump version. 2017-03-03 16:33:32 +01:00
B. Petersen b2a5885787 Show ABI separated from version. 2017-03-03 16:15:35 +01:00
B. Petersen 9886a4feb4 Add advanced settings dialog, remove some upload functions. 2017-03-03 15:26:17 +01:00
B. Petersen dcd04f7064 Remove always-empty-objects. 2017-03-03 15:05:37 +01:00
B. Petersen 5773ce8b83 Update gradle. 2017-03-03 14:38:46 +01:00
B. Petersen 0c3eb19de6 Rewrite settings dialogs. 2017-03-03 14:37:30 +01:00
B. Petersen 5e72e30d58 Fix endless redraw loop for voice message showing. 2017-03-02 23:23:48 +01:00
B. Petersen c9d8ad3d4a Show the status-bar-player for music as well as for voice messages. 2017-03-02 22:26:57 +01:00
B. Petersen 62bd4f6d9f Cleanup some ChatMessageCell conditions. 2017-03-02 21:48:02 +01:00
B. Petersen 15e1d55a77 Send voice messages as voice messages. 2017-03-02 21:22:34 +01:00
B. Petersen 04cab2ee0c Remove webpage message types. 2017-03-02 21:19:51 +01:00
B. Petersen fd28868ea8 Stop player when deselecting an audio track in the audio-select-activity. 2017-03-02 17:43:00 +01:00
B. Petersen 129e6ad487 Do not hide the default-send-key if send-by-enter is enables (looks like a bug). 2017-03-02 16:43:37 +01:00
B. Petersen 082f7229f2 Visualise enabled send-by-enter-function by hiding the normal send-button and showing a send key instead of a new-line-key on the keyboard. 2017-03-02 15:09:29 +01:00
B. Petersen 1c6001ed92 Remove unused top-view from ChatActivityEnterView. 2017-03-02 13:43:27 +01:00
B. Petersen 2ec48ef1e6 Remove unused cancelBotButton. 2017-03-02 13:19:43 +01:00
B. Petersen 04397f3cb0 Remove unused caption-text-view-layout. 2017-03-02 12:51:18 +01:00
B. Petersen 8697756083 Cleanup setting page. 2017-03-02 11:32:07 +01:00
B. Petersen 7be5ec589c Remove unneded permissions. 2017-03-01 22:05:57 +01:00
B. Petersen d3fbf529eb Remove (hopefully) unneeded AbstractThreadedSyncAdapter. 2017-03-01 20:14:39 +01:00
B. Petersen e47818b5df Remove currently unused and not implemented ChooserTargetService. 2017-03-01 18:56:23 +01:00
B. Petersen 201c9ebf4c Remove currently unused AccountAuthenticator service. 2017-03-01 18:36:14 +01:00
B. Petersen 0626192659 Allow 'Open messages' only for messages with an attachment. 2017-03-01 17:57:10 +01:00
B. Petersen 0acdd3f885 Enable basic voice message recording. 2017-03-01 15:18:26 +01:00
B. Petersen 6f0fd1072d Remove disturbing 'big' notification-music-player. Update notification-music-player logo and colors. 2017-03-01 14:22:36 +01:00
B. Petersen d17579b928 Do not expose data through MediaBrowserService, this seems unexpected for an messenger. Instead, the user can use 'save to music' or 'share' explicitly for items not privacy related. 2017-03-01 11:30:39 +01:00
B. Petersen 090039ec29 Remove internal player and rely on the MusicService 2017-02-28 23:18:07 +01:00
B. Petersen df8bbcd00a Orange audio seekbar. 2017-02-28 22:19:23 +01:00
B. Petersen fffc77cc82 Play audio files. 2017-02-28 21:53:49 +01:00
B. Petersen 9ee5af9fd2 Update German. 2017-02-28 20:53:45 +01:00
B. Petersen 5462f3d341 Add 'Open' command for all file types. 2017-02-28 19:15:31 +01:00
B. Petersen 46dca0d212 Remove unused resources. 2017-02-28 18:39:25 +01:00
B. Petersen 603572c796 Remove (hopefully) unneeded ShareBroadcastReceiver class. 2017-02-28 17:45:11 +01:00
B. Petersen db6c2d9d7c Show 'File not found' hint. 2017-02-28 17:03:25 +01:00
B. Petersen b6c6375492 More senseful name for new-chat-from-deaddrop-button. 2017-02-28 16:08:52 +01:00
B. Petersen 3f5255c116 Remove load and cancel buttons from ChatMessageCell, cleanup. 2017-02-28 15:59:15 +01:00
B. Petersen 68f3974aa2 Name button states. 2017-02-28 14:26:45 +01:00
B. Petersen 2c062d8d51 Select and send audio attachments via the music browser. 2017-02-27 22:35:20 +01:00
B. Petersen 1097157f69 Show icon for incoming audio files. 2017-02-27 22:01:52 +01:00
B. Petersen 21784aa951 Simplify and rework message sending. 2017-02-27 19:24:55 +01:00
B. Petersen f980f7285a Remove unused 'Reply'-parameters, continued. 2017-02-27 17:12:04 +01:00
B. Petersen 622b6bc786 Remove unused 'Reply'-parameters. 2017-02-27 16:26:44 +01:00
B. Petersen 61fc0485b7 Unify attach icons. 2017-02-27 12:25:22 +01:00
B. Petersen be2af9c871 Name the request codes. Wondering how this was editable before. 2017-02-24 21:42:31 +01:00
B. Petersen 898e4a45e3 Remove unneeded merge-dialog option. 2017-02-24 20:48:04 +01:00
B. Petersen e47c6406f8 Implement share from chat/photo view. 2017-02-24 19:41:18 +01:00
B. Petersen 1d0ed83bad Implement save to downloads/music/gallery. 2017-02-24 17:34:54 +01:00
Björn Petersen 404f6ea9da Update CHANGELOG.md 2017-02-24 12:00:52 +01:00
B. Petersen 8d75f867fd Add menu buttons for saving and sharing attachments. 2017-02-23 23:59:45 +01:00
B. Petersen 83f60e6252 Remove unused file observers. 2017-02-23 22:44:03 +01:00
B. Petersen c4bd6576d8 Simplify object creation. 2017-02-23 22:43:31 +01:00
B. Petersen 12df911162 Use the standard text view for pincode entering; otherwise, the last entered number is always shown for a moment, independently of the system setting (in fact, for pincodes, currently, the number is _never_ shown as setText() does not work this way; however, this is just fine, much better). 2017-02-23 21:06:53 +01:00
B. Petersen f5a37ee185 Redo false commit. 2017-02-23 20:36:01 +01:00
B. Petersen 92d71ad150 When locking the app, try to clear the screenshot that is shown in the task switcher. 2017-02-23 20:30:15 +01:00
B. Petersen 8824b30c4a Remove unused import. 2017-02-23 16:38:37 +01:00
B. Petersen 741e281a37 Dismiss app when touching the lock-symbol. 2017-02-23 16:37:22 +01:00
B. Petersen 354295ae7a Unify passcode-enter-dialog background. 2017-02-23 15:15:43 +01:00
B. Petersen 09af0640c7 Simplify fingerprint dialog. 2017-02-23 14:50:28 +01:00
B. Petersen 1485eeecf6 Do not use the new AttachmentsContentProvider for pulic URLs as used when attaching local files. 2017-02-23 13:28:31 +01:00
B. Petersen 8b78df6a14 Remove attach size limit. 2017-02-22 23:09:56 +01:00
B. Petersen 686ee6c246 Coloize attachment file name in chat view. 2017-02-22 22:56:32 +01:00
B. Petersen ca8114d9af Simplify and beautify file selector. 2017-02-22 22:33:23 +01:00
B. Petersen b2392c90c2 Use the same colors for the time and for the forward title. 2017-02-22 21:18:51 +01:00
B. Petersen d207fa67e5 Remove unused URL-searching when entering text. 2017-02-22 20:53:13 +01:00
B. Petersen 2e41fe756a Show correct error box when an attachment cannot be opened. 2017-02-22 20:43:05 +01:00
B. Petersen d533ea5c37 Open attachments by using a content provider. 2017-02-22 19:26:18 +01:00
B. Petersen 4365e176d8 Remove dead code. 2017-02-22 17:53:21 +01:00
B. Petersen 486b03e031 Update messenger-backend submodule. 2017-02-22 17:34:15 +01:00
B. Petersen 1dbf08327c Ignore some files. 2017-02-22 16:56:30 +01:00
B. Petersen 0d15bb3544 Add missing file, ignore files marked as .prv (useful for scripts etc.). 2017-02-22 16:18:57 +01:00
B. Petersen e3b48206e9 Remove 'Done'-hint after message deletion; as normally at least one of the selected message is in view when this function is used, there is enough visual feedback (we want the 'Done'-hint only for actions without visual feedback as copy-to-clipboard). 2017-02-22 15:50:25 +01:00
B. Petersen a0e364a50f Show any documents attached (opening still not working). 2017-02-21 23:21:09 +01:00
B. Petersen 0db3fc55c6 Use binary prefix for file sizes. 2017-02-21 22:18:47 +01:00
B. Petersen 95c3fca389 Show some hints on silent actions as copy-to-clipboard or delete-contact. 2017-02-21 21:52:24 +01:00
B. Petersen 68a72fb8fd Typo. 2017-02-21 18:43:15 +01:00
B. Petersen 473410ece2 Change urls to https://getdelta.org . 2017-02-21 18:40:42 +01:00
B. Petersen 4f760a790a Differ betweend music and voice messages. 2017-02-21 17:02:49 +01:00
B. Petersen ad7ee4428f Remove duplicate strings. 2017-02-21 14:28:31 +01:00
B. Petersen 92cf756ad2 Cleanup reply option in ChatMessageCell. 2017-02-20 22:38:24 +01:00
B. Petersen 3d746f08ba Remove unused message object types. 2017-02-20 21:58:25 +01:00
B. Petersen e272459fc9 Use named values for MessageObject.type; wondering how and by whom this was ever usable before. 2017-02-20 21:43:50 +01:00
B. Petersen a793ae52f9 Make file selection dialog usable. 2017-02-20 20:43:18 +01:00
B. Petersen f2349a9bdd Accept vcards shared to us by external apps. Remove unused contact and location code. 2017-02-20 19:12:29 +01:00
B. Petersen 7082798c03 Swap File- and Contact-attach icons. 2017-02-20 14:44:35 +01:00
B. Petersen f4fc5fae2b Cleanup camera preview code. 2017-02-20 13:57:36 +01:00
B. Petersen 5799e43b3a Update Polish. 2017-02-20 11:54:51 +01:00
B. Petersen f929d6cc31 Cleanup SendMessagesHelper.sendMessage__(), fix a crash when trying to send music files. 2017-02-19 13:04:17 +01:00
B. Petersen 9f92efc554 More neutral language when choosing contacts. 2017-02-19 12:14:23 +01:00
B. Petersen 3338b83910 Pimp attach gui. 2017-02-18 23:57:43 +01:00
B. Petersen a4c104431d Show a hint after deletion of a contact. 2017-02-18 22:49:08 +01:00
B. Petersen 31ba521244 Prefer the term 'contact' over 'user', unify usage. 2017-02-18 22:26:16 +01:00
B. Petersen 50dfe15f09 Show a hint if a user is already in a group. 2017-02-18 21:38:04 +01:00
Dr. Tobias Quathamer 4b06d19787 Add item to changelog for v0.1.20 2017-02-18 16:58:27 +01:00
B. Petersen 66d147eb8b Implement sending contact's addresses. 2017-02-17 21:50:31 +01:00
Björn Petersen d2591922a6 Update CHANGELOG.md 2017-02-17 21:14:34 +01:00
B. Petersen bcc6f79373 More options in URL's context menu: Create chat, create user, open externally, copy to clipboard. 2017-02-17 21:03:25 +01:00
B. Petersen 015edd6053 Create a new chat by clicking on email-links. 2017-02-17 19:26:25 +01:00
B. Petersen bec562bfb2 Linkify email-addresses. 2017-02-17 19:08:32 +01:00
B. Petersen 01a7c93771 If an avatar is shown for a message in group layout, make the bubble a little bit smaller. 2017-02-17 17:06:18 +01:00
B. Petersen 502bae625f Cleanup MessageObject. 2017-02-17 16:33:48 +01:00
B. Petersen a34d511922 Update Polish. 2017-02-17 15:50:57 +01:00
B. Petersen e65aa19109 Fix a null-pointer exception when using tablets. 2017-02-17 13:38:23 +01:00
B. Petersen 30585b8de4 More background wallpaper dynamic. 2017-02-16 23:19:09 +01:00
B. Petersen 0bd4234214 Cleanup drawer profile cell. 2017-02-16 22:42:07 +01:00
B. Petersen db4ceb6d68 Prepare release v0.1.20 (we forgot to update the submodule in v0.1.19). 2017-02-16 20:49:29 +01:00
B. Petersen 1612a5d7cd Update messenger-backend submodule. 2017-02-16 20:42:11 +01:00
B. Petersen f60f4539b5 Prepare release v0.1.19 2017-02-16 16:30:38 +01:00
B. Petersen db7c8a9dfc Update changelog. 2017-02-16 15:19:45 +01:00
B. Petersen 9d1f4266c2 Update changelog. 2017-02-15 22:46:07 +01:00
Björn Petersen 0614c4fc32 Update README.md 2017-02-14 19:57:56 +01:00
B. Petersen 58e452b711 Update polish. 2017-02-14 15:26:58 +01:00
Dr. Tobias Quathamer b478696bed Target API level 25 (Nougat 7.1) 2017-02-13 21:19:47 +01:00
B. Petersen f3584d9eaf Update Portuguese. 2017-02-13 20:37:35 +01:00
B. Petersen d9998167f4 Colorize the background image. 2017-02-13 17:59:06 +01:00
Dr. Tobias Quathamer 874e300220 Remove LocaleController calls 2017-02-11 17:48:41 +01:00
Dr. Tobias Quathamer 49e4b90cc3 Remove unused code 2017-02-11 17:42:35 +01:00
Dr. Tobias Quathamer f492f2cd71 Prepare release 0.1.18 2017-02-11 17:23:49 +01:00
Dr. Tobias Quathamer 2800a282ec Update backend to v0.1.18 2017-02-11 17:16:57 +01:00
Dr. Tobias Quathamer 593e93304c Update changelog 2017-02-10 21:43:36 +01:00
Dr. Tobias Quathamer 77b6108ca8 Fix lint warning, use apply() instead of commit().
commit() writes its data to persistent storage immediately,
whereas apply() will handle it in the background.
2017-02-10 21:43:11 +01:00
Dr. Tobias Quathamer 90bf2b6b19 Update changelog 2017-02-10 21:15:05 +01:00
B. Petersen dd91d52df4 Merge branch 'master' of https://github.com/r10s/messenger-android 2017-02-10 21:07:04 +01:00
B. Petersen de29317fa6 Use standard placeholders in local files. 2017-02-10 21:06:54 +01:00
Dr. Tobias Quathamer 44faee6208 Update backend for plural handling 2017-02-10 21:04:45 +01:00
Dr. Tobias Quathamer 41ccf19e58 Fix typo 2017-02-10 21:03:31 +01:00
B. Petersen 05c390980a Support 'plurals'-strings in the backend. 2017-02-10 20:11:02 +01:00
B. Petersen 4446ed0792 Remove unused peer/empty class. 2017-02-10 16:29:58 +01:00
Dr. Tobias Quathamer 11942da0c0 Update changelog 2017-02-10 16:25:24 +01:00
B. Petersen 9a0604a1a8 Update polish translation. 2017-02-10 16:07:11 +01:00
B. Petersen 93ca874e61 Merge branch 'master' of https://github.com/r10s/messenger-android 2017-02-10 15:47:25 +01:00
B. Petersen 9ba21c4346 Colorize settings headlines. 2017-02-10 15:47:08 +01:00
Dr. Tobias Quathamer c0e7798cad Remove class AndroidAuthenticator.
The class is never used and requires the permission USE_CREDENTIALS.
That permission has never been requested, so the code would fail anyway.
2017-02-10 14:40:20 +01:00
Dr. Tobias Quathamer 0aea5a2201 Replace LocaleController 2017-02-10 14:35:27 +01:00
B. Petersen 63873ec1d5 Slightly optimize colors. 2017-02-10 13:58:16 +01:00
B. Petersen 23f269d4b3 Remove complicated and unreliable calculation of shading colors. 2017-02-10 02:01:41 +01:00
B. Petersen 9ebacb23c4 Bold date headlines. 2017-02-10 00:55:38 +01:00
B. Petersen d1e83f46d8 Improve typography, do not mix system font with resource font which looks ugly when not using 'Roboto'. 2017-02-10 00:14:34 +01:00
B. Petersen 5f2dd23a6e Remove unused chat alert and profile search cell. 2017-02-09 22:48:51 +01:00
B. Petersen d29b24e9a6 Cleanup code in the chat activitie's date headlines. 2017-02-09 18:52:01 +01:00
Dr. Tobias Quathamer 4f1415e127 Remove condition which is always true 2017-02-09 14:32:55 +01:00
Dr. Tobias Quathamer c604313c09 Replace LocaleController with android methods 2017-02-09 14:32:08 +01:00
Dr. Tobias Quathamer e6bc14a8de Replace LocaleController with android methods 2017-02-09 14:14:27 +01:00
Dr. Tobias Quathamer 4a5729d371 Remove unneeded translations 2017-02-09 14:06:40 +01:00
Dr. Tobias Quathamer d9ac76a317 Remove custom plural handling from LocaleController 2017-02-09 13:54:39 +01:00
Dr. Tobias Quathamer 867df35d44 Remove unused strings 2017-02-09 11:25:00 +01:00
Dr. Tobias Quathamer e946d61b92 Use android plural handling for 'Times' 2017-02-09 10:30:42 +01:00
Dr. Tobias Quathamer fa2ffbd70f Rewrite more plural handling of 'Days' 2017-02-09 10:03:45 +01:00
Dr. Tobias Quathamer 1123f03134 Use android plural handling for 'Days' 2017-02-09 10:00:09 +01:00
Dr. Tobias Quathamer 49e86d08bf Remove unneeded string 'MuteFor' 2017-02-09 09:50:03 +01:00
Dr. Tobias Quathamer 5f00826e65 Rewrite more plural handling of 'Hours' 2017-02-09 09:48:22 +01:00
Dr. Tobias Quathamer 82382f31f1 Use android plural handling for 'Hours' 2017-02-09 09:37:09 +01:00
Dr. Tobias Quathamer 833cbf7302 Rewrite more plural handling of 'Minutes' 2017-02-09 09:31:53 +01:00
Dr. Tobias Quathamer 4e329adaca Use android plural handling for 'Minutes' 2017-02-08 22:39:31 +01:00
Dr. Tobias Quathamer dbc9e4c3c2 Add German translation 2017-02-08 22:05:33 +01:00
Dr. Tobias Quathamer d9cff40fd5 Remove unneeded translation 'FromChats' 2017-02-08 22:04:20 +01:00
Dr. Tobias Quathamer ef248712d6 Use android plural handling 2017-02-08 22:03:45 +01:00
Dr. Tobias Quathamer 9765ba1bac Remove unneeded plural string 'Stickers' 2017-02-08 19:35:52 +01:00
Dr. Tobias Quathamer afcccaa864 Remove unused class 'StickerSetCell' 2017-02-08 19:34:37 +01:00
Dr. Tobias Quathamer 7caef2ceb9 Remove unneeded plural string 'Photos' 2017-02-08 19:28:25 +01:00
Dr. Tobias Quathamer cb4480ad78 Remove accidentally translated unused strings 2017-02-08 19:27:42 +01:00
Dr. Tobias Quathamer 6388349c16 Remove unneeded tools hints 2017-02-08 19:27:42 +01:00
B. Petersen 73a111aeac Update default wallpaper, get rid of telegram logo there. 2017-02-08 18:15:04 +01:00
Björn Petersen 5869bdc9dd Update CHANGELOG.md 2017-02-08 16:19:39 +01:00
B. Petersen ff7f75abed Add Polish translation file. 2017-02-08 12:13:57 +01:00
B. Petersen 28ac3bd9eb Add Polish translation. 2017-02-08 12:12:33 +01:00
Dr. Tobias Quathamer 49f07874f8 Fix version number in changelog 2017-02-07 22:12:08 +01:00
Dr. Tobias Quathamer 59779b7f2a Prepare release 0.1.17 2017-02-07 22:10:15 +01:00
Dr. Tobias Quathamer 677df359ae Fix plural handling of message deletion 2017-02-07 22:04:33 +01:00
Dr. Tobias Quathamer 4e4aca675f Remove unneeded tools hints 2017-02-07 21:49:07 +01:00
Dr. Tobias Quathamer 76163e6012 Typography: Use ellipsis 2017-02-07 21:39:47 +01:00
Dr. Tobias Quathamer 85b319825d Update Portuguese translation 2017-02-07 21:37:04 +01:00
Dr. Tobias Quathamer 8edf8a6140 Add some more information to the changelog 2017-02-07 21:31:45 +01:00
Dr. Tobias Quathamer acba74142c Add changelog for easier access from F-Droid. Closes #39 2017-02-07 21:14:29 +01:00
Dr. Tobias Quathamer c06f34923e Remove reintroduced strings 2017-02-07 20:29:34 +01:00
B. Petersen bb00342b5d Update portuguese from strings given in issue #38. 2017-02-07 18:22:53 +01:00
Dr. Tobias Quathamer 25b43986d3 Remove unused strings 2017-02-07 12:18:01 +01:00
Dr. Tobias Quathamer 9b5984182f Refactor: Use android plural handling 2017-02-07 12:09:21 +01:00
Dr. Tobias Quathamer ae9dfb1595 Remove unused strings 2017-02-07 10:33:48 +01:00
Dr. Tobias Quathamer 001a4a8675 Remove unused strings 2017-02-07 10:31:15 +01:00
Dr. Tobias Quathamer 13a1e92321 Refactor: Use android plural handling 2017-02-07 10:28:48 +01:00
Dr. Tobias Quathamer fb97c8edaf Refactor: Use android plural handling 2017-02-07 09:55:37 +01:00
Dr. Tobias Quathamer ffce59ea7e Remove unused methods 2017-02-06 18:58:03 +01:00
Dr. Tobias Quathamer dd7ef2d744 Use android's own locale handling 2017-02-06 18:49:13 +01:00
Dr. Tobias Quathamer a76f840368 Remove unused method 2017-02-06 18:37:48 +01:00
Dr. Tobias Quathamer c4bac7359b Remove unused methods and translations 2017-02-06 14:50:32 +01:00
Dr. Tobias Quathamer 67e028502d Refactor: Use android plural handling 2017-02-06 14:39:48 +01:00
Dr. Tobias Quathamer e05b31a76b Remove LocaleController 2017-02-06 14:12:11 +01:00
Dr. Tobias Quathamer d1b95e369d Refactor: Use android plural handling 2017-02-06 14:11:36 +01:00
Dr. Tobias Quathamer 64a71f25f2 Refactor: Use android plural handling 2017-02-06 13:56:51 +01:00
Dr. Tobias Quathamer 76e906579b Really add French translation ... 2017-02-06 13:30:03 +01:00
Dr. Tobias Quathamer 23dc66622b Remove unneeded string resources 2017-02-06 13:01:05 +01:00
Dr. Tobias Quathamer 997bbd336c Comment out unused method 2017-02-06 12:55:06 +01:00
Dr. Tobias Quathamer d8a0225b1a Use only 'fat' productFlavor to speed up build process.
All other flavors are currently not supported by F-Droid, they can
be re-enabled when the app is available through Google Play.
2017-02-06 12:34:48 +01:00
Dr. Tobias Quathamer ce656ca374 Remove unneeded AndroidManifest.xml files and 'foss' build type.
This also drops the permissions ACCESS_COARSE_LOCATION
and ACCESS_FINE_LOCATION which are not used currently.
2017-02-06 11:55:35 +01:00
Dr. Tobias Quathamer dd202b4c72 Add missing android:label to manifest 2017-02-06 11:34:49 +01:00
Dr. Tobias Quathamer 522ff32432 Prepare release 0.1.16 2017-02-06 00:37:07 +01:00
Dr. Tobias Quathamer a96cb520dd Update to backend v0.1.16 2017-02-06 00:32:19 +01:00
Dr. Tobias Quathamer fe9cd52312 Fix some syntax errors 2017-02-05 22:12:29 +01:00
Gilles MOREL d4355ad076 Added French translation 2017-02-05 21:59:37 +01:00
Dr. Tobias Quathamer 057d0eb39e Fix typo 2017-02-05 15:39:47 +01:00
Dr. Tobias Quathamer 82f35621e2 Fix method name typo 2017-02-02 20:46:06 +01:00
Dr. Tobias Quathamer 633856b350 Replace deprecated attribute singleLine with maxLines 2017-02-02 20:00:21 +01:00
Dr. Tobias Quathamer 1c0c9004c6 Convert DOS line endings CRLF to unix line endings, LF. No content changes 2017-02-02 19:59:12 +01:00
Dr. Tobias Quathamer 833533adc3 Remove wrongly lowered TargetAPI 10, project wide is API 14 2017-02-02 17:56:28 +01:00
Dr. Tobias Quathamer 846df6a164 Use a short tag for logging.
There are only 23 characters allowed, the tag
"LinearLayoutManager#LayoutState" was 31 characters.

This fixes a lint error.
2017-01-31 21:20:30 +01:00
Dr. Tobias Quathamer f5de9e8a23 Translate two missing strings 2017-01-31 21:12:01 +01:00
Dr. Tobias Quathamer 404a0ca032 Update Gradle to version 2.14.1 2017-01-31 20:50:40 +01:00
Dr. Tobias Quathamer 6e8612172b Update Android Gradle plugin to version 2.2.3 2017-01-31 20:50:25 +01:00
Dr. Tobias Quathamer aed9e39287 Bump version code for next release 2017-01-31 13:10:38 +01:00
Dr. Tobias Quathamer 597100d9e3 Use new path of backend submodule 2017-01-31 12:27:30 +01:00
Dr. Tobias Quathamer b2775e0811 Include submodule for messenger-backend 2017-01-31 12:16:58 +01:00
Björn Petersen 2425f0dcc7 Merge pull request #17 from toddy15/master
Fix some lint errors and warnings
2017-01-30 18:19:24 +01:00
Dr. Tobias Quathamer ede60340f6 Remove superfluous xmlns from TextView 2017-01-30 16:53:04 +01:00
Dr. Tobias Quathamer a9d58ab3f3 Ignore false positive lint error 2017-01-29 21:05:51 +01:00
Dr. Tobias Quathamer 6d6b6f41c9 Do not fail to build upon lint errors 2017-01-29 19:41:32 +01:00
Dr. Tobias Quathamer f5f97e4bfc Add missing string in default locale 2017-01-29 19:02:22 +01:00
Dr. Tobias Quathamer c7ed50a225 Typography: use ellipsis instead of three dots 2017-01-29 18:56:29 +01:00
Dr. Tobias Quathamer f843c531b4 Typography: use ellipsis instead of three dots 2017-01-29 18:02:33 +01:00
B. Petersen 2389a7d136 Remove bad error message. 2017-01-29 03:13:32 +01:00
B. Petersen e1d0306a29 Typo 2017-01-29 01:27:30 +01:00
B. Petersen 04cbe3f825 Speed up deleting multiple messages. 2017-01-28 18:29:01 +01:00
B. Petersen 9796ac1c53 Show the correct number of unread messages in the home page's icon. 2017-01-28 15:22:43 +01:00
B. Petersen 5721b9f86d Show forwarded headers. 2017-01-27 23:58:00 +01:00
B. Petersen aa090a9cd4 Fix calling forward function. 2017-01-27 12:40:01 +01:00
B. Petersen 03c30bef47 Ask forwarding. 2017-01-26 19:20:43 +01:00
B. Petersen c59453f31b Update colors. 2017-01-26 18:49:11 +01:00
B. Petersen 49e7f19cb7 Prepare forwarding messages. 2017-01-26 17:17:46 +01:00
B. Petersen 469c56f1a6 Pimp selection-action-bar-menu. 2017-01-26 15:17:31 +01:00
B. Petersen 239c56e77d Move copy/reply/info to a submenu in the selection-action-bar-menu. 2017-01-26 01:03:14 +01:00
B. Petersen e32ca20604 Change defaults for functions not yet implemented. 2017-01-24 16:50:15 +01:00
B. Petersen d00ef0af32 Add option to reset a user's encryption key. 2017-01-23 22:45:20 +01:00
B. Petersen e616e57be6 Add E2EE backend file. 2017-01-22 01:05:01 +01:00
B. Petersen 5485db8509 Add E2EE options. 2017-01-21 14:36:47 +01:00
B. Petersen df75d2917f Add options for e2e-encryption and for read receipts. 2017-01-19 18:16:45 +01:00
B. Petersen 0478ea5162 Separate command line stuff from program. 2017-01-19 17:30:29 +01:00
B. Petersen 433e90072f Improve 'no messages' screen and add a hint about greylisting. 2017-01-17 15:06:13 +01:00
B. Petersen 5c646ea663 Show receivers email-address when send messages from extern. 2017-01-16 21:19:43 +01:00
B. Petersen e095d3f886 Cleanup 'Not yet implemented' messages. 2017-01-15 13:18:45 +01:00
B. Petersen 9a6315d0b2 Typo 2017-01-14 17:45:55 +01:00
B. Petersen 8e81f0bb8f Update profile on remote changes.. 2017-01-14 01:47:26 +01:00
B. Petersen d6bdebc865 Localize. 2017-01-14 00:56:29 +01:00
B. Petersen 7ddf368fd1 Cleanup. 2017-01-13 23:19:23 +01:00
B. Petersen 301c6a4430 Increase version. 2017-01-13 18:49:11 +01:00
B. Petersen adaf91e383 Show an error on impossible actions. 2017-01-13 15:18:09 +01:00
B. Petersen 40de9dfe98 Ask before adding/removing members from group. 2017-01-13 11:36:11 +01:00
B. Petersen 18a8e2358c Group name changing and member adding/removing implemented. 2017-01-13 01:09:13 +01:00
B. Petersen e2a4008742 Fix scroll bug. 2017-01-12 17:46:13 +01:00
B. Petersen 258633b672 Propose a message as a draft for new created groups. 2017-01-11 14:36:43 +01:00
B. Petersen 96cc35b84d Add/remove members from group chats. 2017-01-11 01:28:08 +01:00
B. Petersen 787efa3c5d Edit group names. 2017-01-11 00:46:42 +01:00
B. Petersen 848862ae84 Fix a memory leak. 2017-01-11 00:09:50 +01:00
B. Petersen 6d3c170e96 Update avatars on renamings. 2017-01-11 00:01:56 +01:00
B. Petersen a921523014 Add SELF to chat contacts. 2017-01-10 17:07:53 +01:00
B. Petersen 29e5133c63 Create and delete groups. 2017-01-09 23:49:28 +01:00
B. Petersen 8d4aebe8e7 Cleanup. 2017-01-09 21:16:05 +01:00
B. Petersen c0139b1b49 HACK around a keyboard-focus issue. 2017-01-09 17:08:28 +01:00
B. Petersen 920d55ee6d Cleanup, remove unused AOSP files. 2017-01-09 14:53:56 +01:00
B. Petersen 4348b80b02 Show unread count in search message results only if the message itself is unread. 2017-01-09 14:27:12 +01:00
B. Petersen 1a62ed853b Show search summaries. 2017-01-09 14:11:18 +01:00
B. Petersen f858cc7747 Implement global search. 2017-01-09 02:10:10 +01:00
B. Petersen 394b439a06 Explain non-hide-floating. 2017-01-08 21:53:16 +01:00
B. Petersen b515660bac Cleanup locale. 2017-01-08 21:24:20 +01:00
B. Petersen 88719df0af Remove dead mention code. 2017-01-08 21:00:09 +01:00
B. Petersen 495dfa0f59 Force redraw when the query gets empty. 2017-01-08 14:49:57 +01:00
B. Petersen f7372819a1 Pimp in-chat-search. 2017-01-08 14:39:51 +01:00
B. Petersen 9d622ecef7 Show empty bottom overlay on in-chat-search. 2017-01-08 12:56:17 +01:00
B. Petersen 221004354e Move search up/down buttons to action bar; also show the number of hits there. 2017-01-08 02:11:14 +01:00
B. Petersen 442baa6aa9 Implement search 2017-01-07 20:27:38 +01:00
B. Petersen 2e4f748093 Allow using the menu if there is a draft; add 'Attach files' as a normal menu entry to access this function if the normal 'attach' button is replaces by the 'send' button. 2017-01-07 18:26:34 +01:00
B. Petersen 56a846ab3b Remove dead 'mentions' code from ChatActivity. 2017-01-07 15:12:42 +01:00
B. Petersen f67e24b49e Cleanup 2017-01-07 14:36:58 +01:00
B. Petersen f40a3e49cb Also use 'speech bubbles' for photos and media. 2017-01-06 15:57:34 +01:00
B. Petersen 04b815bb49 Clearify coordinates. 2017-01-06 15:39:12 +01:00
B. Petersen 3292979696 Fast loading of large chats. 2017-01-06 02:54:29 +01:00
B. Petersen 3e24ca9be1 Update chat with incoming/outgoing messages. 2017-01-05 18:41:45 +01:00
B. Petersen 38e5350219 Use a virtual listbox for the messages to allow some thousands of messages in a chat. 2017-01-05 15:32:32 +01:00
B. Petersen 39d5c40945 Cleanup keyboard code. 2017-01-05 13:25:26 +01:00
B. Petersen ebcb132acf Cleanup. 2017-01-05 13:10:11 +01:00
B. Petersen 53447c793a Remove dead sticker code. 2017-01-05 12:22:42 +01:00
B. Petersen 54a2df818b Remove unused GIF code from ChatActivity. 2017-01-05 12:10:19 +01:00
B. Petersen 09a3b3bd26 Get rid of unused context menu code. 2017-01-05 11:59:50 +01:00
B. Petersen f02d4cd21a Remove suspicious forward creation of objects. 2017-01-05 02:34:01 +01:00
B. Petersen eb650ff089 Cleanup 2017-01-05 01:10:21 +01:00
B. Petersen da263b1e56 Remove unused service messages. 2017-01-05 00:25:38 +01:00
B. Petersen 44ee4aaef7 Cleanup. 2017-01-05 00:00:45 +01:00
B. Petersen 56874bd418 Cleanup notification strings. 2017-01-04 23:52:20 +01:00
B. Petersen bf1594fdef Use correct avatars for the created widgets. 2017-01-04 01:08:08 +01:00
B. Petersen e31821cf92 Test solid wallpapers. 2017-01-03 18:43:29 +01:00
B. Petersen 4efe3b4387 Go directly to the notified chat. 2017-01-03 17:52:34 +01:00
B. Petersen 69d0537425 Prepare MrChat to get the pointer-handle directly in the C-Part. 2017-01-03 17:20:30 +01:00
B. Petersen 0852e09815 Cleanup headers. 2017-01-03 16:40:43 +01:00
B. Petersen 2fc8799241 Hide unused empty-search-field-buttons (may be seen as close-search-bar-buttons otherwise). 2017-01-03 14:45:08 +01:00
B. Petersen ea01205421 Show correct chat after sharing texts. 2017-01-02 15:35:25 +01:00
B. Petersen 1ad31aa178 Can send share texts to Delta Chat. 2017-01-02 15:25:02 +01:00
B. Petersen 349b943a7e Unify 'disabled' and 'off' strings. 2017-01-02 14:55:31 +01:00
B. Petersen 268006d027 'Repeat notifications' default to 'off'. 2017-01-02 13:02:56 +01:00
B. Petersen e2bad18153 Show number of blocked users in settings. 2017-01-02 12:35:10 +01:00
B. Petersen 4749ddf9a8 Tweak notifications. 2016-12-24 01:33:23 +01:00
B. Petersen de1c568714 Localize 2016-12-23 23:55:49 +01:00
B. Petersen 0b90e66ad8 Tweak notifications. 2016-12-23 14:47:17 +01:00
B. Petersen 90fe75a764 Play notification sounds, vibrate. 2016-12-23 02:15:48 +01:00
B. Petersen c27fd27789 Remove seen messages from notifications. Display user and group names in notifications only if they differ from each other. 2016-12-23 02:08:37 +01:00
B. Petersen 5580f5ae62 Set user and message text in notifications. 2016-12-22 18:44:24 +01:00
B. Petersen d4e94b2fbc Set Delta Chat notification icon. 2016-12-22 12:27:23 +01:00
B. Petersen bb673dd992 Make notifications generally work. 2016-12-21 23:34:28 +01:00
B. Petersen 2dfacc4858 Make 'Reset notifications and sounds' work. 2016-12-21 23:04:52 +01:00
B. Petersen cce4e31b0f Remove popup notifications, for now. 2016-12-21 22:12:40 +01:00
B. Petersen 99615999b8 Re-init stock strings after language change, fixes issue #1. 2016-12-21 21:44:56 +01:00
B. Petersen cfca25d65d Hide button 'Notifications and Sounds' for deaddrops not shown in chatlist. 2016-12-21 21:26:42 +01:00
B. Petersen 665a2cdfd0 Prepare notifications. 2016-12-21 18:13:04 +01:00
B. Petersen a2768728d3 Play in-chat sounds. 2016-12-21 17:47:11 +01:00
B. Petersen 2790082705 Cleanup. 2016-12-21 16:44:31 +01:00
B. Petersen ae8a15d524 Cleanup. 2016-12-21 16:23:10 +01:00
B. Petersen e39d7b5d4d Add an extra event for incoming messages. 2016-12-21 01:17:14 +01:00
B. Petersen 1ae26ecfa5 Cleanup notify code. 2016-12-21 00:38:22 +01:00
B. Petersen 1e58912226 Showing the default font size in the NumberPicker. 2016-12-20 23:57:20 +01:00
B. Petersen 87807db64a Do not use the android cache directory as our 'blob repository'; the cache directory may be treated as a real cache; the files may disappear at any time. Instead, we're using a normal directory beside the database (the directory that is already used by the backend for incoming messages) and delete files ourself as needed. 2016-12-20 22:43:22 +01:00
B. Petersen 6221c97283 For non-empty strings, do not use NewStringUTF() as this is buggy on some Android versions. Instead, create the string using 'new String(ByteArray, 'UTF-8');' which seems to be programmed more properly. (eg. on KitKat a simple 'SMILING FACE WITH SMILING EYES' (U+1F60A, UTF-8 F0 9F 98 8A) will let the app crash, reporting 0xF0 is a bad UTF-8 start, see http://stackoverflow.com/questions/12127817/android-ics-4-0-ndk-newstringutf-is-crashing-down-the-app ) 2016-12-20 00:21:18 +01:00
B. Petersen 80226717b6 Set up photo type. 2016-12-19 16:29:59 +01:00
B. Petersen 959f7af2ab Change intro layout (paging below pages ...). 2016-12-19 14:16:06 +01:00
B. Petersen 2308990661 Cleanup paths. 2016-12-19 13:45:44 +01:00
B. Petersen 9f304f372a Remove save-to-gallery option. We save all stuff internally; this avoids probles if a user deletes an image. Additionally, photos taken are always saved in the gallery; plus, the user can explicitly save data to the gallery (this avoids saving all files twice). 2016-12-19 13:19:16 +01:00
B. Petersen 341580191f Tuning settings dialog. 2016-12-19 00:18:27 +01:00
B. Petersen 07065676f2 Cleanup WebPage stuff. 2016-12-13 12:58:27 +01:00
B. Petersen 47c9dc6e31 Simplify rights management. 2016-12-13 00:15:12 +01:00
B. Petersen 2514494d02 Force reloading avatars, do not clear old values (looks smarter). 2016-12-12 14:32:46 +01:00
B. Petersen 1c28c2d475 Load avatars in working thread, cache avatars, reload avatars after pause (they may have been changed in another app then). 2016-12-12 14:13:04 +01:00
B. Petersen 41a92d56c4 Using a mask instead of clipping to create round avatars; this avoid problems with canvas setting sets and allows antialiasing. 2016-12-12 12:37:36 +01:00
B. Petersen 6a6b024314 Draw avatar photos. 2016-12-10 01:23:38 +01:00
B. Petersen 12c95971a2 Cleanup avatar management, route everything through ContactsController.setupAvatar(). 2016-12-09 17:18:18 +01:00
B. Petersen 62ca3b6331 Neutral language. 2016-12-09 13:58:24 +01:00
B. Petersen c69f2fd75d Add invite function. 2016-12-09 13:10:35 +01:00
B. Petersen 0fc45bc57a Disable hiding of the floating button. 2016-12-08 13:55:36 +01:00
B. Petersen 0b9614f0bd Cleanup. 2016-12-06 14:13:37 +01:00
B. Petersen e8a073a42c Cleanup. 2016-12-06 14:00:53 +01:00
B. Petersen 97b33ec9c4 Cleanup. 2016-12-06 12:56:17 +01:00
B. Petersen f6458870ae Optimize unread display. 2016-12-06 12:38:52 +01:00
B. Petersen 665f24db1e Smart 'message seen' handling. 2016-12-05 23:55:32 +01:00
B. Petersen a59be9d2af Mark incoming messages as read when seen. 2016-12-05 22:56:02 +01:00
B. Petersen 1036139cb7 Properly add date headlines. 2016-12-05 22:30:45 +01:00
B. Petersen f1854e46be Cleanup. 2016-12-05 15:10:59 +01:00
B. Petersen bfad3e57c7 Remove unneeded reply functionality. 2016-12-05 14:01:32 +01:00
B. Petersen 24ee24325b Remove unneded loading cells. 2016-12-05 13:45:10 +01:00
B. Petersen c9f6db312f Remove unneded mergeDialogId stuff from ChatActivity. 2016-12-05 13:27:54 +01:00
B. Petersen 6f60ba113e Remove ChatObject class. 2016-12-05 12:29:07 +01:00
B. Petersen db112b226e Remove DraftQuery, StickersQuery, SharedMediaQuery & Co. 2016-12-05 12:20:26 +01:00
B. Petersen a87049e443 Cleanup. 2016-12-04 23:45:41 +01:00
B. Petersen 730b018b45 Cleanup. 2016-12-04 22:46:32 +01:00
B. Petersen 60e72f14d8 Simplify chat objects. 2016-12-03 18:48:09 +01:00
B. Petersen e89b2855ce Remove UserObject.isDeleted(). 2016-12-03 18:06:52 +01:00
1235 changed files with 14103 additions and 103583 deletions
+3
View File
@@ -6,3 +6,6 @@ obj/
local.properties
*.keystore
libs/
# ignore private scripts and directories, eg. local2github.prv.sh
*.prv*
+3
View File
@@ -0,0 +1,3 @@
[submodule "MessengerProj/jni/messenger-backend"]
path = MessengerProj/jni/messenger-backend
url = https://github.com/r10s/messenger-backend.git
+106
View File
@@ -0,0 +1,106 @@
# Delta Chat Changelog
## v0.1.28
2017-04-14
* Pimp notifications
* Bug fixes
## v0.1.27
2017-04-12
* Use a permanent foreground service for reliable notifications
* Monitor the IMAP-IDLE thread and reconnect if IMAP-IDLE seems to hang
* Various battery and background optimizations
## v0.1.25
2017-04-04
* Use system or user selected video player.
* Do not connect if not configured (avoids a warning on the first time startup)
* Add vertical scrollbar, eg. to settings activities.
* Pimp GUI and logo.
* Update Korean.
## v0.1.24
2017-03-31
* Share images and documents from other apps to Delta Chat
* Offer to mailto:-link-support to other apps
* Ignore implausible sending time of incoming messages; use the receive time in these rare cases
* Show errors only when Delta Chat is in foreground
* Dynamically adapt video bitrate for longer videos to an attachment-size of max. 25 MB
## v0.1.23
2017-03-28
* Retry connecting to IMAP if there is not network available on the first try
* Notify about new messages if the app is not active for hours, optimize battery consumption
## v0.1.22
2017-03-22
* Show HTML-only messages
* Show connection errors
* Add options for SSL/TLS and STARTTLS
* Automatic account configuration, if possible
* Recode large videos
* Add Hungarian translation
* Add Korean translation
## v0.1.21
2017-03-10
* Record and send voice messages
* Record and send videos
* Send and play music
* Send contacts and email addresses
* Sending and opening attachments of any type
* Share and open commands for all attachments
* Accept VCards send to us by other apps
* Clickable email addresses
* Update Polish translation
* Fix tablet startup bug
* Close the app when using the lock-app-via-pincode function
* Protect data by using a content provider for sharing
* Try to clear the task switcher's screenshots when locking the app via pincode
* Pimp GUI
## v0.1.20
2017-02-16
* Avoid unwanted downloads of lots of old messages
* Make the "Chats" folder visible if the server hides new folders by default
* Fix a crash when the server returns empty folders
* Update Polish and Portuguese translations
* Use API level 25 (Nougat 7.1) as target
## v0.1.18
2017-02-11
* Add Polish translation
* Use a new default background for chats
* Improve typography by using the system font instead of a custom resource font
* Remove custom plural handling, use Android's routines instead
* Remove unused source code and strings
* More fixes of lint errors and warnings
## v0.1.17
2017-02-07
* Drop two unnecessary permissions: ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION
* Really add French translation
* Update Portuguese translation
* Start fixing translation handling of the program
* Remove special "foss" build, because the whole program is free now.
## v0.1.16
2017-02-06
* Add French translation
* Fix some lint errors and warnings
## v0.1.15
2017-01-31
* Prepare for release on [F-Droid](https://f-droid.org/)
+13 -26
View File
@@ -24,15 +24,15 @@ tasks.withType(JavaCompile) {
}
dependencies {
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:appcompat-v7:25.1.1'
compile 'com.googlecode.mp4parser:isoparser:1.0.6'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
}
android {
compileSdkVersion 23
buildToolsVersion '23.0.3'
compileSdkVersion 25
buildToolsVersion '25.0.2'
useLibrary 'org.apache.http.legacy'
defaultConfig.applicationId = "com.b44t.messenger"
@@ -42,6 +42,10 @@ android {
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
signingConfigs {
debug {
storeFile file("config/debug.keystore")
@@ -70,34 +74,17 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
foss {
debuggable false
jniDebuggable false
signingConfig signingConfigs.release
}
}
defaultConfig.versionCode = 13
defaultConfig.versionCode = 28
sourceSets.main {
jniLibs.srcDir 'libs'
jni.srcDirs = [] //disable automatic ndk-build call
}
sourceSets.debug {
manifest.srcFile 'config/debug/AndroidManifest.xml'
}
sourceSets.release {
manifest.srcFile 'config/release/AndroidManifest.xml'
}
sourceSets.foss {
manifest.srcFile 'config/foss/AndroidManifest.xml'
}
productFlavors {
/*
x86 {
ndk {
abiFilter "x86"
@@ -116,6 +103,7 @@ android {
}
versionCode = 1
}
*/
fat {
versionCode = 3
}
@@ -127,9 +115,8 @@ android {
}
defaultConfig {
minSdkVersion 14 // 14: Android 4.0 Ice Cream Sandwich 2011 (Telegram default), 21: Android 5.0 Lollipop 2014 (recommended for InstantRun)
targetSdkVersion 23
versionName "0.1.4"
minSdkVersion 14 // 14: Android 4.0 Ice Cream Sandwich 2011 (Telegram default), 21: Android 5.0 Lollipop 2014 (recommended for InstantRun)
targetSdkVersion 25 // 25: Nougat. CAVE: Do NOT target "Andoid O" without checking the background tasks carefully, see https://developer.android.com/preview/behavior-changes.html#back-all . As long as we target "Nougat", everything works as expected even for "Andoid O" or later
versionName "0.1.28" // do NOT forget to increase defaultConfig.versionCode!
}
}
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.b44t.messenger"
android:installLocation="auto">
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.LOCATION" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/AppNameBeta"
android:theme="@style/Theme.MessengerProj.Start"
android:name=".ApplicationLoader"
android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:largeHeap="true">
</application>
</manifest>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.b44t.messenger"
android:installLocation="auto">
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.MessengerProj.Start"
android:name=".ApplicationLoader"
android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:largeHeap="true">
</application>
</manifest>
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.b44t.messenger"
android:installLocation="auto">
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.LOCATION" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.MessengerProj.Start"
android:name=".ApplicationLoader"
android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:largeHeap="true">
</application>
</manifest>
+23 -20
View File
@@ -1598,30 +1598,33 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
endif
LOCAL_SRC_FILES += \
./jni.c \
./mrjnimain.c \
./audio.c \
./utils.c \
./image.c \
./video.c \
./gifvideo.cpp \
../../../messenger-backend/src/mrchat.c \
../../../messenger-backend/src/mrchatlist.c \
../../../messenger-backend/src/mrcontact.c \
../../../messenger-backend/src/mrimap.c \
../../../messenger-backend/src/mrjob.c \
../../../messenger-backend/src/mrlog.c \
../../../messenger-backend/src/mrloginparam.c \
../../../messenger-backend/src/mrmailbox.c \
../../../messenger-backend/src/mrmimeparser.c \
../../../messenger-backend/src/mrmsg.c \
../../../messenger-backend/src/mrosnative.c \
../../../messenger-backend/src/mrparam.c \
../../../messenger-backend/src/mrpoortext.c \
../../../messenger-backend/src/mrsimplify.c \
../../../messenger-backend/src/mrsmtp.c \
../../../messenger-backend/src/mrsqlite3.c \
../../../messenger-backend/src/mrstock.c \
../../../messenger-backend/src/mrtools.c \
./messenger-backend/src/mrchat.c \
./messenger-backend/src/mrchatlist.c \
./messenger-backend/src/mrcmdline.c \
./messenger-backend/src/mrcontact.c \
./messenger-backend/src/mre2ee.c \
./messenger-backend/src/mrimap.c \
./messenger-backend/src/mrjob.c \
./messenger-backend/src/mrloginparam.c \
./messenger-backend/src/mrmailbox.c \
./messenger-backend/src/mrmailbox_configure.c \
./messenger-backend/src/mrmailbox_log.c \
./messenger-backend/src/mrmimeparser.c \
./messenger-backend/src/mrmsg.c \
./messenger-backend/src/mrosnative.c \
./messenger-backend/src/mrparam.c \
./messenger-backend/src/mrpoortext.c \
./messenger-backend/src/mrsaxparser.c \
./messenger-backend/src/mrsimplify.c \
./messenger-backend/src/mrsmtp.c \
./messenger-backend/src/mrsqlite3.c \
./messenger-backend/src/mrstock.c \
./messenger-backend/src/mrtools.c \
./mrwrapper.c
include $(BUILD_SHARED_LIBRARY)
+64 -40
View File
@@ -1,3 +1,26 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#include <jni.h>
#include <ogg/ogg.h>
#include <stdio.h>
@@ -6,7 +29,7 @@
#include <time.h>
#include <opusfile.h>
#include <math.h>
#include "utils.h"
#include "mrjnimain.h"
typedef struct {
int version;
@@ -115,7 +138,7 @@ static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
return 1;
}
int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len) {
static int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len) {
int i;
Packet p;
unsigned char ch;
@@ -219,34 +242,34 @@ static int writeOggPage(ogg_page *page, FILE *os) {
return written;
}
const opus_int32 bitrate = 16000;
const opus_int32 rate = 16000;
const opus_int32 frame_size = 960;
const int with_cvbr = 1;
const int max_ogg_delay = 0;
const int comment_padding = 512;
static const opus_int32 bitrate = 16000;
static const opus_int32 rate = 16000;
static const opus_int32 frame_size = 960;
static const int with_cvbr = 1;
static const int max_ogg_delay = 0;
static const int comment_padding = 512;
opus_int32 coding_rate = 16000;
ogg_int32_t _packetId;
OpusEncoder *_encoder = 0;
uint8_t *_packet = 0;
ogg_stream_state os;
FILE *_fileOs = 0;
oe_enc_opt inopt;
OpusHeader header;
opus_int32 min_bytes;
int max_frame_bytes;
ogg_packet op;
ogg_page og;
opus_int64 bytes_written;
opus_int64 pages_out;
opus_int64 total_samples;
ogg_int64_t enc_granulepos;
ogg_int64_t last_granulepos;
int size_segments;
int last_segments;
static opus_int32 coding_rate = 16000;
static ogg_int32_t _packetId;
static OpusEncoder *_encoder = 0;
static uint8_t *_packet = 0;
static ogg_stream_state os;
static FILE *_fileOs = 0;
static oe_enc_opt inopt;
static OpusHeader header;
static opus_int32 min_bytes;
static int max_frame_bytes;
static ogg_packet op;
static ogg_page og;
static opus_int64 bytes_written;
static opus_int64 pages_out;
static opus_int64 total_samples;
static ogg_int64_t enc_granulepos;
static ogg_int64_t last_granulepos;
static int size_segments;
static int last_segments;
void cleanupRecorder() {
static void cleanupRecorder() {
ogg_stream_flush(&os, &og);
@@ -282,7 +305,7 @@ void cleanupRecorder() {
memset(&og, 0, sizeof(ogg_page));
}
int initRecorder(const char *path) {
static int initRecorder(const char *path) {
cleanupRecorder();
if (!path) {
@@ -421,7 +444,7 @@ int initRecorder(const char *path) {
return 1;
}
int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) {
static int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) {
int cur_frame_size = frame_size;
_packetId++;
@@ -527,15 +550,15 @@ JNIEXPORT void Java_com_b44t_messenger_MediaController_stopRecord(JNIEnv *env, j
}
//player
OggOpusFile *_opusFile;
int _isSeekable = 0;
int64_t _totalPcmDuration = 0;
int64_t _currentPcmOffset = 0;
int _finished = 0;
static OggOpusFile *_opusFile;
static int _isSeekable = 0;
static int64_t _totalPcmDuration = 0;
static int64_t _currentPcmOffset = 0;
static int _finished = 0;
static const int playerBuffersCount = 3;
static const int playerSampleRate = 48000;
void cleanupPlayer() {
static void cleanupPlayer() {
if (_opusFile) {
op_free(_opusFile);
_opusFile = 0;
@@ -546,7 +569,7 @@ void cleanupPlayer() {
_finished = 0;
}
int seekPlayer(float position) {
static int seekPlayer(float position) {
if (!_opusFile || !_isSeekable || position < 0) {
return 0;
}
@@ -559,7 +582,7 @@ int seekPlayer(float position) {
return result == OPUS_OK;
}
int initPlayer(const char *path) {
static int initPlayer(const char *path) {
cleanupPlayer();
int openError = OPUS_OK;
@@ -576,7 +599,7 @@ int initPlayer(const char *path) {
return 1;
}
void fillBuffer(uint8_t *buffer, int capacity, int *args) {
static void fillBuffer(uint8_t *buffer, int capacity, int *args) {
if (_opusFile) {
args[1] = max(0, op_pcm_tell(_opusFile));
@@ -735,7 +758,7 @@ JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform2(JNIEnv
return result;
}
int16_t *sampleBuffer = NULL;
static int16_t *sampleBuffer = NULL;
JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) {
@@ -819,3 +842,4 @@ JNIEXPORT jbyteArray Java_com_b44t_messenger_MediaController_getWaveform(JNIEnv
return result;
}
+30 -11
View File
@@ -1,5 +1,28 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#include <jni.h>
#include <utils.h>
#include "mrjnimain.h"
#include <libyuv.h>
#include <android/bitmap.h>
#include <cstdint>
@@ -53,19 +76,14 @@ typedef struct VideoInfo {
AVPacket orig_pkt;
};
jobject makeGlobarRef(JNIEnv *env, jobject object) {
if (object) {
return env->NewGlobalRef(object);
}
return 0;
}
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env) {
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env) { /* called from JNI_OnLoad() */
av_register_all();
return 0;
}
int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
static int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
int ret;
AVStream *st;
AVCodecContext *dec_ctx = NULL;
@@ -97,7 +115,7 @@ int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaTy
return 0;
}
int decode_packet(VideoInfo *info, int *got_frame) {
static int decode_packet(VideoInfo *info, int *got_frame) {
int ret = 0;
int decoded = info->pkt.size;
@@ -263,4 +281,5 @@ jint Java_com_b44t_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env,
}
return 0;
}
}
} /* extern "C" */
+33
View File
@@ -0,0 +1,33 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#ifndef __GIFVIDEO_H__
#define __GIFVIDEO_H__
#include <jni.h>
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env);
#endif /* __GIFVIDEO_H__ */
+52 -15
View File
@@ -1,3 +1,26 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#include <jni.h>
#include <stdio.h>
#include <setjmp.h>
@@ -5,21 +28,35 @@
#include <android/bitmap.h>
#include <libwebp/webp/decode.h>
#include <libwebp/webp/encode.h>
#include "utils.h"
#include "mrjnimain.h"
#include "image.h"
jclass jclass_NullPointerException;
jclass jclass_RuntimeException;
jclass jclass_Options;
jfieldID jclass_Options_inJustDecodeBounds;
jfieldID jclass_Options_outHeight;
jfieldID jclass_Options_outWidth;
static jclass jclass_NullPointerException;
static jclass jclass_RuntimeException;
const uint32_t PGPhotoEnhanceHistogramBins = 256;
const uint32_t PGPhotoEnhanceSegments = 4;
static jclass jclass_Options;
static jfieldID jclass_Options_inJustDecodeBounds;
static jfieldID jclass_Options_outHeight;
static jfieldID jclass_Options_outWidth;
jclass createGlobarRef(JNIEnv *env, jclass class) {
static const uint32_t PGPhotoEnhanceHistogramBins = 256;
static const uint32_t PGPhotoEnhanceSegments = 4;
static void throwException(JNIEnv *env, char *format, ...) {
jclass exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
if (!exClass) {
return;
}
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
(*env)->ThrowNew(env, exClass, dest);
}
static jclass createGlobalRef(JNIEnv *env, jclass class) {
if (class) {
return (*env)->NewGlobalRef(env, class);
}
@@ -27,16 +64,16 @@ jclass createGlobarRef(JNIEnv *env, jclass class) {
}
jint imageOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) {
jclass_NullPointerException = createGlobarRef(env, (*env)->FindClass(env, "java/lang/NullPointerException"));
jclass_NullPointerException = createGlobalRef(env, (*env)->FindClass(env, "java/lang/NullPointerException"));
if (jclass_NullPointerException == 0) {
return -1;
}
jclass_RuntimeException = createGlobarRef(env, (*env)->FindClass(env, "java/lang/RuntimeException"));
jclass_RuntimeException = createGlobalRef(env, (*env)->FindClass(env, "java/lang/RuntimeException"));
if (jclass_RuntimeException == 0) {
return -1;
}
jclass_Options = createGlobarRef(env, (*env)->FindClass(env, "android/graphics/BitmapFactory$Options"));
jclass_Options = createGlobalRef(env, (*env)->FindClass(env, "android/graphics/BitmapFactory$Options"));
if (jclass_Options == 0) {
return -1;
}
@@ -262,7 +299,7 @@ typedef struct my_error_mgr {
} *my_error_ptr;
METHODDEF(void) my_error_exit(j_common_ptr cinfo) {
METHODDEF(void) my_jpeglib_error_exit(j_common_ptr cinfo) {
my_error_ptr myerr = (my_error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
@@ -424,7 +461,7 @@ JNIEXPORT void Java_com_b44t_messenger_Utilities_loadBitmap(JNIEnv *env, jclass
struct jpeg_decompress_struct cinfo;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
jerr.pub.error_exit = my_jpeglib_error_exit;
if (!setjmp(jerr.setjmp_buffer)) {
jpeg_create_decompress(&cinfo);
+29 -3
View File
@@ -1,8 +1,34 @@
#ifndef image_h
#define image_h
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#ifndef __IMAGE_H__
#define __IMAGE_H__
#include <jni.h>
jint imageOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env);
#endif
#endif /* __IMAGE_H__ */
-67
View File
@@ -1,67 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdlib.h>
#include <openssl/aes.h>
#include <unistd.h>
#include "utils.h"
#include "image.h"
int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) { /* this function is called automatically by the JNI when the library gets loaded */
JNIEnv *env = 0;
srand(time(NULL));
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
if (imageOnJNILoad(vm, reserved, env) == -1) {
return -1;
}
if (gifvideoOnJNILoad(vm, env) == -1) {
return -1;
}
return JNI_VERSION_1_6;
}
void JNI_OnUnload(JavaVM *vm, void *reserved) {
}
/*
JNIEXPORT void Java_com_b44t_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, jboolean encrypt, int offset, int length) {
jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset;
unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL);
unsigned char *ivBuff = (unsigned char *)(*env)->GetByteArrayElements(env, iv, NULL);
AES_KEY akey;
if (!encrypt) {
AES_set_decrypt_key(keyBuff, 32 * 8, &akey);
AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_DECRYPT);
} else {
AES_set_encrypt_key(keyBuff, 32 * 8, &akey);
AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_ENCRYPT);
}
(*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0);
}
*/
JNIEXPORT jstring Java_com_b44t_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
static char buf[1000];
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
int result = readlink(fileName, buf, 999);
jstring value = 0;
if (result != -1) {
buf[result] = '\0';
value = (*env)->NewStringUTF(env, buf);
}
(*env)->ReleaseStringUTFChars(env, path, fileName);
return value;
}
@@ -122,13 +122,13 @@
#define LIBETPAN_REENTRANT 1
/* Define this to the version of libEtPan */
#define LIBETPAN_VERSION "1.2-dev-20141203"
//#define LIBETPAN_VERSION "1.2-dev-20141203"
/* Define this to the major version of libEtPan */
#define LIBETPAN_VERSION_MAJOR 1
//#define LIBETPAN_VERSION_MAJOR 1
/* Define this to the minor version of libEtPan */
#define LIBETPAN_VERSION_MINOR 2
//#define LIBETPAN_VERSION_MINOR 2
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
@@ -144,7 +144,7 @@
#define PACKAGE_NAME "libetpan"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libetpan 1.2"
//#define PACKAGE_STRING "libetpan 1.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libetpan"
@@ -153,7 +153,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.2"
//#define PACKAGE_VERSION "1.2"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
@@ -171,7 +171,7 @@
#define USE_SSL 1
/* Version number of package */
#define VERSION "1.2"
//#define VERSION "1.2"
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
+77
View File
@@ -0,0 +1,77 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdlib.h>
#include <openssl/aes.h>
#include <unistd.h>
#include "mrjnimain.h"
#include "image.h"
#include "gifvideo.h"
jint JNI_OnLoad(JavaVM *vm, void *reserved) { /* this function is called automatically by the JNI when the library gets loaded */
JNIEnv *env = 0;
srand(time(NULL));
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI_OnLoad() ..."); /* please note, that __android_log_print() may not work (eg. on LG X Cam), however, we don't have an option here. */
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
if (imageOnJNILoad(vm, reserved, env) == -1) {
return -1;
}
if (gifvideoOnJNILoad(vm, env) == -1) {
return -1;
}
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI_OnLoad() succeeded.");
return JNI_VERSION_1_6;
}
void JNI_OnUnload(JavaVM *vm, void *reserved) {
}
JNIEXPORT jstring Java_com_b44t_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
static char buf[1000];
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
int result = readlink(fileName, buf, 999);
jstring value = 0;
if (result != -1) {
buf[result] = '\0';
value = (*env)->NewStringUTF(env, buf);
}
(*env)->ReleaseStringUTFChars(env, path, fileName);
return value;
}
+54
View File
@@ -0,0 +1,54 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#ifndef __MRJNIMAIN_H__
#define __MRJNIMAIN_H__
#include <android/log.h>
#include <jni.h>
#define LOG_TAG "DeltaChat"
#ifndef LOG_DISABLED
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(...)
#define LOGD(...)
#define LOGE(...)
#define LOGV(...)
#endif
#ifndef max
#define max(x, y) ((x) > (y)) ? (x) : (y)
#endif
#ifndef min
#define min(x, y) ((x) < (y)) ? (x) : (y)
#endif
#endif /* __MRJNIMAIN_H__*/
+387 -116
View File
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,15 +20,14 @@
*******************************************************************************
*
* File: mr_wrapper.c
* Authors: Björn Petersen
* Purpose: The C part of the Java<->C Wrapper, see also MrMailbox.java
*
******************************************************************************/
#include <jni.h>
#include <android/log.h>
#include "../../../messenger-backend/src/mrmailbox.h"
#include "messenger-backend/src/mrmailbox.h"
#define CHAR_REF(a) \
@@ -37,49 +36,81 @@
#define CHAR_UNREF(a) \
if(a) { (*env)->ReleaseStringUTFChars(env, (a), a##Ptr); }
#define JSTRING_NEW(a) \
(*env)->NewStringUTF(env, a? a : "") /*should handle NULL arguments, does not return NULL!*/
/* our log handler */
static void s_log_callback_(int type, const char* msg)
#define JSTRING_NEW(a) jstring_new__(env, (a))
static jstring jstring_new__(JNIEnv* env, const char* a)
{
int prio;
switch( type ) {
case 'd': prio = ANDROID_LOG_DEBUG; break;
case 'i': prio = ANDROID_LOG_INFO; break;
case 'w': prio = ANDROID_LOG_WARN; break;
default: prio = ANDROID_LOG_ERROR; break;
if( a==NULL || a[0]==0 ) {
return (*env)->NewStringUTF(env, "");
}
__android_log_print(prio, "DeltaChat", "%s\n", msg); /* on problems, add `-llog` to `Android.mk` */
/* for non-empty strings, do not use NewStringUTF() as this is buggy on some Android versions.
Instead, create the string using `new String(ByteArray, "UTF-8);` which seems to be programmed more properly.
(eg. on KitKat a simple "SMILING FACE WITH SMILING EYES" (U+1F60A, UTF-8 F0 9F 98 8A) will let the app crash, reporting 0xF0 is a bad UTF-8 start,
see http://stackoverflow.com/questions/12127817/android-ics-4-0-ndk-newstringutf-is-crashing-down-the-app ) */
static jclass s_strCls = NULL;
static jmethodID s_strCtor = NULL;
static jclass s_strEncode = NULL;
if( s_strCls==NULL ) {
s_strCls = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/lang/String"));
s_strCtor = (*env)->GetMethodID(env, s_strCls, "<init>", "([BLjava/lang/String;)V");
s_strEncode = (*env)->NewGlobalRef(env, (*env)->NewStringUTF(env, "UTF-8"));
}
int a_bytes = strlen(a);
jbyteArray array = (*env)->NewByteArray(env, a_bytes);
(*env)->SetByteArrayRegion(env, array, 0, a_bytes, a);
jstring ret = (jstring) (*env)->NewObject(env, s_strCls, s_strCtor, array, s_strEncode);
(*env)->DeleteLocalRef(env, array); /* we have to delete the reference as it is not returned to Java, AFAIK */
return ret;
}
/* globl stuff */
/* global stuff */
static JavaVM* s_jvm = NULL;
static jclass s_MrMailbox_class = NULL;
static jmethodID s_MrCallback_methodID = NULL;
static int s_global_init_done = 0;
static void s_init_globals(JNIEnv *env, jclass MrMailbox_class)
{
/* make sure, the intialisation is done only once */
static bool s_global_init_done = 0;
if( s_global_init_done ) { return; }
s_global_init_done = 1;
/* init global callback */
mrlog_set_handler(s_log_callback_);
/* prepare calling back a Java function */
__android_log_print(ANDROID_LOG_INFO, "DeltaChat", "JNI: s_init_globals()..."); /* low-level logging, mrmailbox_log_*() may not be yet available. However, please note that __android_log_print() may not work (eg. on LG X Cam) */
(*env)->GetJavaVM(env, &s_jvm); /* JNIEnv cannot be shared between threads, so we share the JavaVM object */
s_MrMailbox_class = (*env)->NewGlobalRef(env, MrMailbox_class);
s_MrCallback_methodID = (*env)->GetStaticMethodID(env, MrMailbox_class, "MrCallback","(IJJ)J" /*signature as "(param)ret" with I=int, J=long*/ );
}
/* system-specific backend initialisations */
mrosnative_init_android(env); /*this should be called before any other "important" routine is called*/
/* setup threads, only called directly by the backed */
int mrosnative_setup_thread(mrmailbox_t* mailbox)
{
if( s_jvm == NULL ) {
mrmailbox_log_error(mailbox, 0, "Not ready, cannot setup thread.");
return 0;
}
mrmailbox_log_info(mailbox, 0, "Attaching C-thread to Java VM...");
JNIEnv* env = NULL;
(*s_jvm)->AttachCurrentThread(s_jvm, &env, NULL);
mrmailbox_log_info(mailbox, 0, "Attaching ok.");
return 1;
}
void mrosnative_unsetup_thread(mrmailbox_t* mailbox)
{
mrmailbox_log_info(mailbox, 0, "Detaching C-thread from Java VM...");
(*s_jvm)->DetachCurrentThread(s_jvm);
mrmailbox_log_info(mailbox, 0, "DeltaChat", "Detaching done.");
}
@@ -112,6 +143,33 @@ static jintArray carray2jintArray_n_carray_free(JNIEnv *env, const carray* ca)
}
static uint32_t* jintArray2uint32Pointer(JNIEnv* env, jintArray ja, int* ret_icnt)
{
uint32_t* ret = NULL;
if( env && ja && ret_icnt )
{
int i, icnt = (*env)->GetArrayLength(env, ja);
if( icnt > 0 )
{
const jint* temp = (*env)->GetIntArrayElements(env, ja, NULL);
if( temp )
{
ret = calloc(icnt, sizeof(uint32_t));
if( ret )
{
for( i = 0; i < icnt; i++ ) {
ret[i] = (uint32_t)temp[i];
}
*ret_icnt = icnt;
}
(*env)->ReleaseIntArrayElements(env, ja, temp, 0);
}
}
}
return ret;
}
/*******************************************************************************
* MrMailbox
******************************************************************************/
@@ -137,15 +195,24 @@ static uintptr_t s_mailbox_callback_(mrmailbox_t* mailbox, int event, uintptr_t
jlong l;
JNIEnv* env;
#if 0 /* -- __android_log_print() does not log eg. on LG X Cam - but Javas Log.i() etc. do. So, we do not optimize these calls and just use the Java logging. */
if( event==MR_EVENT_INFO || event==MR_EVENT_WARNING ) {
__android_log_print(event==MR_EVENT_INFO? ANDROID_LOG_INFO : ANDROID_LOG_WARN, "DeltaChat", "%s", (char*)data2); /* on problems, add `-llog` to `Android.mk` */
return 0; /* speed up things for info/warning */
}
else if( event == MR_EVENT_ERROR ) {
__android_log_print(ANDROID_LOG_ERROR, "DeltaChat", "%s", (char*)data2);
/* errors are also forwarded to Java to show them in a bubble or so */
}
#endif
if( s_jvm==NULL || s_MrMailbox_class==NULL || s_MrCallback_methodID==NULL ) {
s_log_callback_('e', "Callback called but JavaVM not ready.");
return 0;
return 0; /* may happen on startup */
}
(*s_jvm)->GetEnv(s_jvm, &env, JNI_VERSION_1_6); /* as this function may be called from _any_ thread, we cannot use a static pointer to JNIEnv */
if( env==NULL ) {
s_log_callback_('e', "Callback called but cannot get JNIEnv.");
return 0;
return 0; /* may happen on startup */
}
l = (*env)->CallStaticLongMethod(env, s_MrMailbox_class, s_MrCallback_methodID, (jint)event, (jlong)data1, (jlong)data2);
@@ -162,76 +229,78 @@ JNIEXPORT jlong Java_com_b44t_messenger_MrMailbox_MrMailboxNew(JNIEnv *env, jcla
/* MrMailbox - open/configure/connect/fetch */
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxOpen(JNIEnv *env, jclass c, jlong hMailbox, jstring dbfile, jstring blobdir)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_open(JNIEnv *env, jclass cls, jstring dbfile)
{
CHAR_REF(dbfile);
CHAR_REF(blobdir);
jint ret = mrmailbox_open((mrmailbox_t*)hMailbox, dbfilePtr, blobdirPtr);
CHAR_UNREF(blobdir);
jint ret = mrmailbox_open(get_mrmailbox_t(env, cls), dbfilePtr, NULL);
CHAR_UNREF(dbfile)
return ret;
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_MrMailboxClose(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_close(JNIEnv *env, jclass cls)
{
mrmailbox_close((mrmailbox_t*)hMailbox);
mrmailbox_close(get_mrmailbox_t(env, cls));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxConfigure(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_getBlobdir(JNIEnv *env, jclass cls)
{
return mrmailbox_configure((mrmailbox_t*)hMailbox);
mrmailbox_t* ths = get_mrmailbox_t(env, cls);
return JSTRING_NEW((ths&&ths->m_blobdir)? ths->m_blobdir : NULL);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxIsConfigured(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_configureAndConnect(JNIEnv *env, jclass cls)
{
return (jint)mrmailbox_is_configured((mrmailbox_t*)hMailbox);
mrmailbox_configure_and_connect(get_mrmailbox_t(env, cls));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxConnect(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_configureCancel(JNIEnv *env, jclass cls)
{
return mrmailbox_connect((mrmailbox_t*)hMailbox);
mrmailbox_configure_cancel(get_mrmailbox_t(env, cls));
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_MrMailboxDisconnect(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_isConfigured(JNIEnv *env, jclass cls)
{
mrmailbox_disconnect((mrmailbox_t*)hMailbox);
return (jint)mrmailbox_is_configured(get_mrmailbox_t(env, cls));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxFetch(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_connect(JNIEnv *env, jclass cls)
{
return mrmailbox_fetch((mrmailbox_t*)hMailbox);
mrmailbox_connect(get_mrmailbox_t(env, cls));
}
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_getErrorDescr(JNIEnv *env, jclass cls)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_disconnect(JNIEnv *env, jclass cls)
{
char* c = mrmailbox_get_error_descr(get_mrmailbox_t(env, cls));
jstring ret = JSTRING_NEW(c);
free(c);
return ret;
mrmailbox_disconnect(get_mrmailbox_t(env, cls));
}
/* MrMailbox - handle contacts */
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetKnownContacts(JNIEnv *env, jclass c, jlong hMailbox, jstring query)
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getKnownContacts(JNIEnv *env, jclass cls, jstring query)
{
CHAR_REF(query);
carray* ca = mrmailbox_get_known_contacts((mrmailbox_t*)hMailbox, queryPtr);
CHAR_REF(query);
carray* ca = mrmailbox_get_known_contacts(get_mrmailbox_t(env, cls), queryPtr);
CHAR_UNREF(query);
return carray2jintArray_n_carray_free(env, ca);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetBlockedContacts(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_getBlockedCount(JNIEnv *env, jclass cls)
{
carray* ca = mrmailbox_get_blocked_contacts((mrmailbox_t*)hMailbox);
return mrmailbox_get_blocked_count(get_mrmailbox_t(env, cls));
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getBlockedContacts(JNIEnv *env, jclass cls)
{
carray* ca = mrmailbox_get_blocked_contacts(get_mrmailbox_t(env, cls));
return carray2jintArray_n_carray_free(env, ca);
}
@@ -267,9 +336,18 @@ JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxDeleteContact(JNIEnv *
/* MrMailbox - handle chats */
JNIEXPORT jlong Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatlist(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT jlong Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatlist(JNIEnv *env, jclass c, jlong hMailbox, jstring query)
{
return (jlong)mrmailbox_get_chatlist((mrmailbox_t*)hMailbox);
jlong ret;
if( query ) {
CHAR_REF(query);
ret = (jlong)mrmailbox_get_chatlist((mrmailbox_t*)hMailbox, queryPtr);
CHAR_UNREF(query);
}
else {
ret = (jlong)mrmailbox_get_chatlist((mrmailbox_t*)hMailbox, NULL);
}
return ret;
}
@@ -279,27 +357,69 @@ JNIEXPORT jlong Java_com_b44t_messenger_MrMailbox_MrMailboxGetChat(JNIEnv *env,
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatIdByContactId(JNIEnv *env, jclass c, jlong hMailbox, jint contact_id)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_getChatIdByContactId(JNIEnv *env, jclass cls, jint contact_id)
{
return (jint)mrmailbox_get_chat_id_by_contact_id((mrmailbox_t*)hMailbox, contact_id);
return (jint)mrmailbox_get_chat_id_by_contact_id(get_mrmailbox_t(env, cls), contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxMarkseenChat(JNIEnv *env, jclass c, jlong hMailbox, jint chat_id)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_markseenMsg(JNIEnv *env, jclass cls, jint msg_id)
{
return (jlong)mrmailbox_markseen_chat((mrmailbox_t*)hMailbox, chat_id);
return (jint)mrmailbox_markseen_msg(get_mrmailbox_t(env, cls), msg_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxCreateChatByContactId(JNIEnv *env, jclass c, jlong hMailbox, jint contact_id)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_markseenChat(JNIEnv *env, jclass cls, jint chat_id)
{
return (jint)mrmailbox_create_chat_by_contact_id((mrmailbox_t*)hMailbox, contact_id);
return (jlong)mrmailbox_markseen_chat(get_mrmailbox_t(env, cls), chat_id);
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_MrMailboxDeleteChat(JNIEnv *env, jclass c, jlong hMailbox, jint chat_id)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_createChatByContactId(JNIEnv *env, jclass cls, jint contact_id)
{
mrmailbox_delete_chat((mrmailbox_t*)hMailbox, chat_id);
return (jint)mrmailbox_create_chat_by_contact_id(get_mrmailbox_t(env, cls), contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_createGroupChat(JNIEnv *env, jclass cls, jstring name)
{
CHAR_REF(name);
jint ret = (jint)mrmailbox_create_group_chat(get_mrmailbox_t(env, cls), namePtr);
CHAR_UNREF(name);
return ret;
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_isContactInChat(JNIEnv *env, jclass cls, jint chat_id, jint contact_id)
{
return (jint)mrmailbox_is_contact_in_chat(get_mrmailbox_t(env, cls), chat_id, contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_addContactToChat(JNIEnv *env, jclass cls, jint chat_id, jint contact_id)
{
return (jint)mrmailbox_add_contact_to_chat(get_mrmailbox_t(env, cls), chat_id, contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_removeContactFromChat(JNIEnv *env, jclass cls, jint chat_id, jint contact_id)
{
return (jint)mrmailbox_remove_contact_from_chat(get_mrmailbox_t(env, cls), chat_id, contact_id);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_setChatName(JNIEnv *env, jclass cls, jint chat_id, jstring name)
{
CHAR_REF(name);
jint ret = (jint)mrmailbox_set_chat_name(get_mrmailbox_t(env, cls), chat_id, namePtr);
CHAR_UNREF(name);
return ret;
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_deleteChat(JNIEnv *env, jclass cls, jint chat_id)
{
mrmailbox_delete_chat(get_mrmailbox_t(env, cls), chat_id);
}
@@ -320,30 +440,49 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxGetMsgInfo(JNIEnv *
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_MrMailboxDeleteMsg(JNIEnv *env, jclass c, jlong hMailbox, jint id)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_deleteMsgs(JNIEnv *env, jclass cls, jintArray msg_ids)
{
mrmailbox_delete_msg((mrmailbox_t*)hMailbox, id);
int msg_ids_cnt;
const uint32_t* msg_ids_ptr = jintArray2uint32Pointer(env, msg_ids, &msg_ids_cnt);
mrmailbox_delete_msgs(get_mrmailbox_t(env, cls), msg_ids_ptr, msg_ids_cnt);
free(msg_ids_ptr);
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_forwardMsgs(JNIEnv *env, jclass cls, jintArray msg_ids, jint chat_id)
{
int msg_ids_cnt;
const uint32_t* msg_ids_ptr = jintArray2uint32Pointer(env, msg_ids, &msg_ids_cnt);
mrmailbox_forward_msgs(get_mrmailbox_t(env, cls), msg_ids_ptr, msg_ids_cnt, chat_id);
free(msg_ids_ptr);
}
/* MrMailbox - handle config */
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxSetConfig(JNIEnv *env, jclass c, jlong hMailbox, jstring key, jstring value)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_setConfig(JNIEnv *env, jclass cls, jstring key, jstring value)
{
CHAR_REF(key);
CHAR_REF(value);
jint ret = (jint)mrmailbox_set_config((mrmailbox_t*)hMailbox, keyPtr, valuePtr);
mrmailbox_set_config(get_mrmailbox_t(env, cls), keyPtr, valuePtr);
CHAR_UNREF(key);
CHAR_UNREF(value);
return ret;
}
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxGetConfig(JNIEnv *env, jclass c, jlong hMailbox, jstring key, jstring def)
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_setConfigInt(JNIEnv *env, jclass cls, jstring key, jint value)
{
CHAR_REF(key);
mrmailbox_set_config_int(get_mrmailbox_t(env, cls), keyPtr, value);
CHAR_UNREF(key);
}
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_getConfig(JNIEnv *env, jclass cls, jstring key, jstring def)
{
CHAR_REF(key);
CHAR_REF(def);
char* temp = mrmailbox_get_config((mrmailbox_t*)hMailbox, keyPtr, defPtr);
char* temp = mrmailbox_get_config(get_mrmailbox_t(env, cls), keyPtr, defPtr);
jstring ret = JSTRING_NEW(temp);
free(temp);
CHAR_UNREF(key);
@@ -352,10 +491,10 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxGetConfig(JNIEnv *e
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxGetConfigInt(JNIEnv *env, jclass c, jlong hMailbox, jstring key, jint def)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_getConfigInt(JNIEnv *env, jclass cls, jstring key, jint def)
{
CHAR_REF(key);
jint ret = mrmailbox_get_config_int((mrmailbox_t*)hMailbox, keyPtr, def);
jint ret = mrmailbox_get_config_int(get_mrmailbox_t(env, cls), keyPtr, def);
CHAR_UNREF(key);
return ret;
}
@@ -363,19 +502,19 @@ JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxGetConfigInt(JNIEnv *e
/* MrMailbox - misc. */
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxGetInfo(JNIEnv *env, jclass c, jlong hMailbox)
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_getInfo(JNIEnv *env, jclass cls)
{
char* temp = mrmailbox_get_info((mrmailbox_t*)hMailbox);
char* temp = mrmailbox_get_info(get_mrmailbox_t(env, cls));
jstring ret = JSTRING_NEW(temp);
free(temp);
return ret;
}
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxExecute(JNIEnv *env, jclass c, jlong hMailbox, jstring cmd)
JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_cmdline(JNIEnv *env, jclass cls, jstring cmd)
{
CHAR_REF(cmd);
char* temp = mrmailbox_execute((mrmailbox_t*)hMailbox, cmdPtr);
char* temp = mrmailbox_cmdline(get_mrmailbox_t(env, cls), cmdPtr);
jstring ret = JSTRING_NEW(temp);
free(temp);
CHAR_UNREF(cmd);
@@ -383,6 +522,12 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_MrMailboxExecute(JNIEnv *env
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_heartbeat(JNIEnv *env, jclass cls)
{
mrmailbox_heartbeat(get_mrmailbox_t(env, cls));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_MrMailboxAddAddressBook(JNIEnv *env, jclass c, jlong hMailbox, jstring adrbook)
{
CHAR_REF(adrbook);
@@ -427,42 +572,63 @@ JNIEXPORT jlong Java_com_b44t_messenger_MrChatlist_MrChatlistGetSummaryByIndex(J
******************************************************************************/
static mrchat_t* get_mrchat_t(JNIEnv *env, jobject obj)
{
static jfieldID fid = 0;
if( fid == 0 ) {
jclass cls = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, cls, "m_hChat", "J" /*Signature, J=long*/);
}
if( fid ) {
return (mrchat_t*)(*env)->GetLongField(env, obj, fid);
}
return NULL;
}
JNIEXPORT void Java_com_b44t_messenger_MrChat_MrChatUnref(JNIEnv *env, jclass c, jlong hChat)
{
mrchat_unref((mrchat_t*)hChat);
}
JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatGetId(JNIEnv *env, jclass c, jlong hChat)
JNIEXPORT jint Java_com_b44t_messenger_MrChat_getId(JNIEnv *env, jclass cls)
{
mrchat_t* ths = (mrchat_t*)hChat; if( ths == NULL ) { return 0; }
mrchat_t* ths = get_mrchat_t(env, cls); if( ths == NULL ) { return 0; }
return ths->m_id;
}
JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatGetType(JNIEnv *env, jclass c, jlong hChat)
JNIEXPORT jint Java_com_b44t_messenger_MrChat_getType(JNIEnv *env, jclass cls)
{
mrchat_t* ths = (mrchat_t*)hChat; if( ths == NULL ) { return 0; }
mrchat_t* ths = get_mrchat_t(env, cls); if( ths == NULL ) { return 0; }
return ths->m_type;
}
JNIEXPORT jstring Java_com_b44t_messenger_MrChat_MrChatGetName(JNIEnv *env, jclass c, jlong hChat)
JNIEXPORT jstring Java_com_b44t_messenger_MrChat_getName(JNIEnv *env, jclass cls)
{
mrchat_t* ths = (mrchat_t*)hChat; if( ths == NULL ) { return JSTRING_NEW(NULL); }
mrchat_t* ths = get_mrchat_t(env, cls); if( ths == NULL ) { return JSTRING_NEW(NULL); }
return JSTRING_NEW(ths->m_name);
}
JNIEXPORT jstring Java_com_b44t_messenger_MrChat_MrChatGetSubtitle(JNIEnv *env, jclass c, jlong hChat)
JNIEXPORT jstring Java_com_b44t_messenger_MrChat_getSubtitle(JNIEnv *env, jclass cls)
{
const char* temp = mrchat_get_subtitle((mrchat_t*)hChat);
const char* temp = mrchat_get_subtitle(get_mrchat_t(env, cls));
jstring ret = JSTRING_NEW(temp);
free(temp);
return ret;
}
JNIEXPORT jint Java_com_b44t_messenger_MrChat_getParamInt(JNIEnv *env, jclass cls, jint key, jint def)
{
mrchat_t* ths = get_mrchat_t(env, cls);
return mrparam_get_int(ths? ths->m_param:NULL, key, def);
}
JNIEXPORT jstring Java_com_b44t_messenger_MrChat_MrChatGetDraft(JNIEnv *env, jclass c, jlong hChat) /* returns NULL for "no draft" */
{
mrchat_t* ths = (mrchat_t*)hChat;
@@ -508,20 +674,20 @@ JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatSetDraft(JNIEnv *env, jclass
}
JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatSendText(JNIEnv *env, jclass c, jlong hChat, jstring text)
JNIEXPORT jint Java_com_b44t_messenger_MrChat_sendText(JNIEnv *env, jclass cls, jstring text)
{
mrmsg_t* msg = mrmsg_new();
msg->m_type = MR_MSG_TEXT;
CHAR_REF(text);
msg->m_text = textPtr? strdup(textPtr) : NULL;
CHAR_UNREF(text);
jint msg_id = mrchat_send_msg((mrchat_t*)hChat, msg);
jint msg_id = mrchat_send_msg(get_mrchat_t(env, cls), msg);
mrmsg_unref(msg);
return msg_id;
}
JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatSendMedia(JNIEnv *env, jclass c, jlong hChat, jint type, jstring file, jstring mime, jint w, jint h, jint ms)
JNIEXPORT jint Java_com_b44t_messenger_MrChat_sendMedia(JNIEnv *env, jclass cls, jint type, jstring file, jstring mime, jint w, jint h, jint ms, jstring author, jstring trackname)
{
mrmsg_t* msg = mrmsg_new();
msg->m_type = type;
@@ -535,33 +701,62 @@ JNIEXPORT jint Java_com_b44t_messenger_MrChat_MrChatSendMedia(JNIEnv *env, jclas
mrparam_set_int(msg->m_param, 'w', w);
mrparam_set_int(msg->m_param, 'h', h);
}
if( type == MR_MSG_AUDIO || type == MR_MSG_VIDEO ) {
if( type == MR_MSG_AUDIO || type == MR_MSG_VOICE || type == MR_MSG_VIDEO ) {
mrparam_set_int(msg->m_param, 'd', ms);
}
jint msg_id = mrchat_send_msg((mrchat_t*)hChat, msg);
if( type == MR_MSG_AUDIO ) {
CHAR_REF(author);
mrparam_set(msg->m_param, 'N', authorPtr);
CHAR_UNREF(author);
CHAR_REF(trackname);
mrparam_set(msg->m_param, 'n', tracknamePtr);
CHAR_UNREF(trackname);
}
jint msg_id = mrchat_send_msg(get_mrchat_t(env, cls), msg);
mrmsg_unref(msg);
return msg_id;
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatMedia(JNIEnv *env, jclass c, jlong hMailbox, jint chat_id, jint msg_type, jint or_msg_type)
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getChatMedia(JNIEnv *env, jclass cls, jint chat_id, jint msg_type, jint or_msg_type)
{
carray* ca = mrmailbox_get_chat_media((mrmailbox_t*)hMailbox, chat_id, msg_type, or_msg_type);
carray* ca = mrmailbox_get_chat_media(get_mrmailbox_t(env, cls), chat_id, msg_type, or_msg_type);
return carray2jintArray_n_carray_free(env, ca);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatMsgs(JNIEnv *env, jclass c, jlong hMailbox, jint chat_id)
JNIEXPORT jint Java_com_b44t_messenger_MrMailbox_getNextMedia(JNIEnv *env, jclass cls, jint msg_id, jint dir)
{
carray* ca = mrmailbox_get_chat_msgs((mrmailbox_t*)hMailbox, chat_id);
return mrmailbox_get_next_media(get_mrmailbox_t(env, cls), msg_id, dir);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getChatMsgs(JNIEnv *env, jclass cls, jint chat_id, jint flags, jint marker1before)
{
carray* ca = mrmailbox_get_chat_msgs(get_mrmailbox_t(env, cls), chat_id, flags, marker1before);
return carray2jintArray_n_carray_free(env, ca);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatContacts(JNIEnv *env, jclass c, jlong hMailbox, jint chat_id)
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_searchMsgs(JNIEnv *env, jclass cls, jint chat_id, jstring query)
{
carray* ca = mrmailbox_get_chat_contacts((mrmailbox_t*)hMailbox, chat_id);
CHAR_REF(query);
carray* ca = mrmailbox_search_msgs(get_mrmailbox_t(env, cls), chat_id, queryPtr);
CHAR_UNREF(query);
return carray2jintArray_n_carray_free(env, ca);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getUnseenMsgs(JNIEnv *env, jclass cls)
{
carray* ca = mrmailbox_get_unseen_msgs(get_mrmailbox_t(env, cls));
return carray2jintArray_n_carray_free(env, ca);
}
JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_getChatContacts(JNIEnv *env, jclass cls, jint chat_id)
{
carray* ca = mrmailbox_get_chat_contacts(get_mrmailbox_t(env, cls), chat_id);
return carray2jintArray_n_carray_free(env, ca);
}
@@ -571,6 +766,20 @@ JNIEXPORT jintArray Java_com_b44t_messenger_MrMailbox_MrMailboxGetChatContacts(J
******************************************************************************/
static mrmsg_t* get_mrmsg_t(JNIEnv *env, jobject obj)
{
static jfieldID fid = 0;
if( fid == 0 ) {
jclass cls = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, cls, "m_hMsg", "J" /*Signature, J=long*/);
}
if( fid ) {
return (mrmsg_t*)(*env)->GetLongField(env, obj, fid);
}
return NULL;
}
JNIEXPORT void Java_com_b44t_messenger_MrMsg_MrMsgUnref(JNIEnv *env, jclass c, jlong hMsg)
{
mrmsg_unref((mrmsg_t*)hMsg);
@@ -633,9 +842,9 @@ JNIEXPORT jint Java_com_b44t_messenger_MrMsg_MrMsgGetToId(JNIEnv *env, jclass c,
}
JNIEXPORT jstring Java_com_b44t_messenger_MrMsg_MrMsgGetParam(JNIEnv *env, jclass c, jlong hMsg, jint key, jstring def)
JNIEXPORT jstring Java_com_b44t_messenger_MrMsg_getParam(JNIEnv *env, jobject obj, jint key, jstring def)
{
mrmsg_t* ths = (mrmsg_t*)hMsg;
mrmsg_t* ths = get_mrmsg_t(env, obj);
CHAR_REF(def);
char* temp = mrparam_get(ths? ths->m_param:NULL, key, defPtr);
jstring ret = JSTRING_NEW(temp);
@@ -645,10 +854,68 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMsg_MrMsgGetParam(JNIEnv *env, jclas
}
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_MrMsgGetParamInt(JNIEnv *env, jclass c, jlong hMsg, jint key, jint def)
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_getParamInt(JNIEnv *env, jobject obj, jint key, jint def)
{
mrmsg_t* ths = (mrmsg_t*)hMsg;
return mrparam_get_int(ths? ths->m_param:NULL, key, def);
mrmsg_t* ths = get_mrmsg_t(env, obj);
return mrparam_get_int(ths? ths->m_param:NULL, key, def);
}
JNIEXPORT void Java_com_b44t_messenger_MrMsg_setParamInt(JNIEnv *env, jobject obj, jint key, jint value)
{
mrmsg_t* ths = get_mrmsg_t(env, obj);
mrparam_set_int(ths? ths->m_param:NULL, key, value);
}
JNIEXPORT void Java_com_b44t_messenger_MrMsg_saveParamToDisk(JNIEnv *env, jobject obj)
{
mrmsg_save_param_to_disk(get_mrmsg_t(env, obj));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_getBytes(JNIEnv *env, jobject obj)
{
jint ret = 0;
mrmsg_t* ths = get_mrmsg_t(env, obj);
if( ths ) {
const char* file = mrparam_get(ths->m_param, 'f', NULL);
if( file ) {
ret = mr_get_filebytes(file);
free(file);
}
}
return ret;
}
JNIEXPORT jlong Java_com_b44t_messenger_MrMsg_getSummaryCPtr(JNIEnv *env, jobject obj, jlong hChat)
{
return (jlong)mrmsg_get_summary(get_mrmsg_t(env, obj), (mrchat_t*)hChat);
}
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_getSummarytext(JNIEnv *env, jobject obj, jint approx_characters)
{
return JSTRING_NEW(mrmsg_get_summarytext(get_mrmsg_t(env, obj), approx_characters));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_getFilename(JNIEnv *env, jobject obj)
{
return JSTRING_NEW(mrmsg_get_filename(get_mrmsg_t(env, obj)));
}
JNIEXPORT jlong Java_com_b44t_messenger_MrMsg_getMediainfoCPtr(JNIEnv *env, jobject obj)
{
return (jlong)mrmsg_get_mediainfo(get_mrmsg_t(env, obj));
}
JNIEXPORT jint Java_com_b44t_messenger_MrMsg_isIncreation(JNIEnv *env, jobject obj)
{
return (jint)mrmsg_is_increation(get_mrmsg_t(env, obj));
}
@@ -695,24 +962,24 @@ JNIEXPORT void Java_com_b44t_messenger_MrPoortext_MrPoortextUnref(JNIEnv *env, j
}
JNIEXPORT jstring Java_com_b44t_messenger_MrPoortext_MrPoortextGetTitle(JNIEnv *env, jclass c, jlong hPoortext)
JNIEXPORT jstring Java_com_b44t_messenger_MrPoortext_MrPoortextGetText1(JNIEnv *env, jclass c, jlong hPoortext)
{
mrpoortext_t* ths = (mrpoortext_t*)hPoortext; if( ths == NULL ) { return JSTRING_NEW(NULL); }
return JSTRING_NEW(ths->m_title);
return JSTRING_NEW(ths->m_text1);
}
JNIEXPORT jint Java_com_b44t_messenger_MrPoortext_MrPoortextGetTitleMeaning(JNIEnv *env, jclass c, jlong hPoortext)
JNIEXPORT jint Java_com_b44t_messenger_MrPoortext_MrPoortextGetText1Meaning(JNIEnv *env, jclass c, jlong hPoortext)
{
mrpoortext_t* ths = (mrpoortext_t*)hPoortext; if( ths == NULL ) { return 0; }
return ths->m_title_meaning;
return ths->m_text1_meaning;
}
JNIEXPORT jstring Java_com_b44t_messenger_MrPoortext_MrPoortextGetText(JNIEnv *env, jclass c, jlong hPoortext)
JNIEXPORT jstring Java_com_b44t_messenger_MrPoortext_MrPoortextGetText2(JNIEnv *env, jclass c, jlong hPoortext)
{
mrpoortext_t* ths = (mrpoortext_t*)hPoortext; if( ths == NULL ) { return JSTRING_NEW(NULL); }
return JSTRING_NEW(ths->m_text);
return JSTRING_NEW(ths->m_text2);
}
@@ -746,11 +1013,15 @@ JNIEXPORT jstring Java_com_b44t_messenger_MrMailbox_CPtr2String(JNIEnv *env, jcl
}
JNIEXPORT void Java_com_b44t_messenger_MrMailbox_MrStockAddStr(JNIEnv* env, jclass c, jint id, jstring str)
JNIEXPORT jlong Java_com_b44t_messenger_MrMailbox_String2CPtr(JNIEnv *env, jclass c, jstring str)
{
CHAR_REF(str);
mrstock_add_str(id, strPtr);
CHAR_UNREF(str)
char* hStr = NULL;
if( str ) {
CHAR_REF(str);
hStr = strdup(strPtr);
CHAR_UNREF(str);
}
return (jlong)hStr;
}
-14
View File
@@ -1,14 +0,0 @@
#include "utils.h"
void throwException(JNIEnv *env, char *format, ...) {
jclass exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException");
if (!exClass) {
return;
}
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
(*env)->ThrowNew(env, exClass, dest);
}
-29
View File
@@ -1,29 +0,0 @@
#ifndef log_h
#define log_h
#include <android/log.h>
#include <jni.h>
#define LOG_TAG "DeltaChat"
#ifndef LOG_DISABLED
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(...)
#define LOGD(...)
#define LOGE(...)
#define LOGV(...)
#endif
#ifndef max
#define max(x, y) ((x) > (y)) ? (x) : (y)
#endif
#ifndef min
#define min(x, y) ((x) < (y)) ? (x) : (y)
#endif
void throwException(JNIEnv *env, char *format, ...);
#endif
+26 -2
View File
@@ -1,6 +1,30 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
#include <jni.h>
#include <libyuv.h>
#include <utils.h>
#include "mrjnimain.h"
enum COLOR_FORMATTYPE {
COLOR_FormatMonochrome = 1,
@@ -52,7 +76,7 @@ enum COLOR_FORMATTYPE {
COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00
};
int isSemiPlanarYUV(int colorFormat) {
static int isSemiPlanarYUV(int colorFormat) {
switch (colorFormat) {
case COLOR_FormatYUV420Planar:
case COLOR_FormatYUV420PackedPlanar:
+38 -43
View File
@@ -20,34 +20,35 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- we need it eg. for getActiveNetworkInfo() -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - required for AccountManager -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<!-- <uses-permission android:name="android.permission.WRITE_CONTACTS" /> -->
<!-- <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/> - required for AccountManager in API level <= 22 -->
<!-- <uses-permission android:name="android.permission.READ_PROFILE"/> - required for ContactsContract.Profile -->
<!-- <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/> required for AbstractThreadedSyncAdapter-->
<!-- <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> - required for AbstractThreadedSyncAdapter -->
<!-- <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/> - seems to be unneeded and is no longer supported by Android, was needed for AbstractAccountAuthenticator, see http://stackoverflow.com/questions/32601456/marshmallow-permission-implementation#36907308 -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> - required for windows using the TYPE_SYSTEM_ALERT flag -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- we need the TelephonyManager to pause the audio player on calls -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
<!--<uses-permission android:name="android.permission.CAMERA" />-->
<!-- <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" /> - required for AndroidUtilities.uninstallShortcut() -->
<!-- <uses-permission android:name="android.permission.CAMERA" /> - also disabled in T'gram; we're using the camera via an intent only -->
<application
android:name=".ApplicationLoader"
android:allowBackup="false"
android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:icon="@drawable/ic_launcher"
android:label="@string/AppName"
android:largeHeap="true"
android:theme="@style/Theme.MessengerProj.Start"
android:manageSpaceActivity="com.b44t.ui.ManageSpaceActivity">
@@ -98,22 +99,13 @@
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="vnd.android.cursor.item/vnd.com.b44t.messenger.android.profile"/>
</intent-filter>
<!-- <intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="t'gram.me" android:scheme="http" />
<data android:host="t'gram.me" android:scheme="https" />
<data android:host="t'gram.dog" android:scheme="http" />
<data android:host="t'gram.dog" android:scheme="https" />
</intent-filter> -->
<!-- <intent-filter android:icon="@drawable/ic_launcher" android:priority="1">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tg" />
</intent-filter> -->
<meta-data android:name="android.service.chooser.chooser_target_service" android:value=".TgChooserTargetService" />
<action android:name="android.intent.action.SENDTO"/> <!-- VIEW seems to be standard, however, SENDTO is also mentioned in some examples -->
<data android:scheme="mailto"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
<activity
android:name="com.b44t.ui.ManageSpaceActivity"
@@ -131,15 +123,6 @@
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:exported="true">
</activity>
<activity
android:name="com.b44t.ui.PopupNotificationActivity"
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity=""
android:theme="@style/Theme.MessengerProj.PopupNotification"
android:windowSoftInputMode="adjustResize|stateHidden">
</activity>
<receiver
android:name=".AutoMessageHeardReceiver"
@@ -165,6 +148,7 @@
</receiver>
-->
<!-- currently, we do not use the android account system
<service android:name=".AuthenticatorService" android:exported="true">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
@@ -172,7 +156,9 @@
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/auth"/>
</service>
-->
<!-- seems to be not needed, derived from AbstractThreadedSyncAdapter, would need the READ/WRITE_SYNC_SETTINGS
<service android:name=".ContactsSyncAdapterService" android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
@@ -182,7 +168,11 @@
<meta-data android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
-->
<!-- this would implement the "direct share" functionality (the system shows some direct links eg.
to the most recent chats when calling "share" from another app, see https://developer.android.com/reference/android/service/chooser/ChooserTargetService.html )
however, if we want this feature, we have to implement a ChooserTargetService and add <meta-data android:name="android.service.chooser.chooser_target_service" android:value=".OurChooserTargetService" />
<service
android:name="com.b44t.messenger.TgChooserTargetService"
android:label="@string/AppName"
@@ -190,18 +180,18 @@
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
</service> -->
<service android:name=".NotificationsService" android:enabled="true"/>
<service android:name=".KeepAliveService" android:enabled="true"/>
<service android:name=".NotificationRepeat" android:exported="false"/>
<service android:name=".ClearCacheService" android:exported="false"/>
<service android:name=".VideoEncodingService" android:enabled="true"/>
<service android:name=".MusicPlayerService" android:exported="true" android:enabled="true"/>
<!-- Do not expose data through MediaBrowserService, this seems unexpected for an messenger.
Instead, the user can use 'save to music' or 'share' explicitly for items not privacy related.
<service android:name=".MusicBrowserService" android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
</service> -->
<receiver android:name=".MusicPlayerReceiver" >
<intent-filter>
@@ -215,9 +205,8 @@
</intent-filter>
</receiver>
<receiver android:name=".AppStartReceiver" android:enabled="true">
<receiver android:name=".BootCompletedReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.b44t.start" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
@@ -225,10 +214,16 @@
<receiver android:name=".WearReplyReceiver" android:enabled="true"/>
<!-- <receiver android:name=".NetworkAlarm" android:enabled="true"/> -->
<!-- seems to be unneeded (bp)
<receiver android:name=".ShareBroadcastReceiver" android:enabled="true"/>
-->
<receiver android:name=".TimerReceiver" android:enabled="true"/>
<receiver android:name=".NotificationDismissReceiver" android:exported="false"/>
<provider android:name=".AttachmentsContentProvider" android:authorities="${applicationId}.attachments" android:exported="true" />
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false" />
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632dp" />
Binary file not shown.
-232
View File
@@ -1,232 +0,0 @@
1876;JM;Jamaica;XXX XXXX
1869;KN;Saint Kitts & Nevis;XXX XXXX
1868;TT;Trinidad & Tobago;XXX XXXX
1784;VC;Saint Vincent & the Grenadines;XXX XXXX
1767;DM;Dominica;XXX XXXX
1758;LC;Saint Lucia;XXX XXXX
1721;SX;Sint Maarten;XXX XXXX
1684;AS;American Samoa;XXX XXXX
1671;GU;Guam;XXX XXXX
1670;MP;Northern Mariana Islands;XXX XXXX
1664;MS;Montserrat;XXX XXXX
1649;TC;Turks & Caicos Islands;XXX XXXX
1473;GD;Grenada;XXX XXXX
1441;BM;Bermuda;XXX XXXX
1345;KY;Cayman Islands;XXX XXXX
1340;VI;US Virgin Islands;XXX XXXX
1284;VG;British Virgin Islands;XXX XXXX
1268;AG;Antigua & Barbuda;XXX XXXX
1264;AI;Anguilla;XXX XXXX
1246;BB;Barbados;XXX XXXX
1242;BS;Bahamas;XXX XXXX
998;UZ;Uzbekistan;XX XXXXXXX
996;KG;Kyrgyzstan;XXX XXXXXX
995;GE;Georgia;XXX XXX XXX
994;AZ;Azerbaijan;XX XXX XXXX
993;TM;Turkmenistan;XX XXXXXX
992;TJ;Tajikistan;XX XXX XXXX
977;NP;Nepal;XX XXXX XXXX
976;MN;Mongolia;XX XX XXXX
975;BT;Bhutan;XX XXX XXX
974;QA;Qatar;XX XXX XXX
973;BH;Bahrain;XXXX XXXX
972;IL;Israel;XX XXX XXXX
971;AE;United Arab Emirates;XX XXX XXXX
970;PS;Palestine;XXX XX XXXX
968;OM;Oman;XXXX XXXX
967;YE;Yemen;XXX XXX XXX
966;SA;Saudi Arabia;XX XXX XXXX
965;KW;Kuwait;XXXX XXXX
964;IQ;Iraq;XXX XXX XXXX
963;SY;Syria;XXX XXX XXX
962;JO;Jordan;X XXXX XXXX
961;LB;Lebanon
960;MV;Maldives;XXX XXXX
886;TW;Taiwan;XXX XXX XXX
880;BD;Bangladesh
856;LA;Laos;XX XX XXX XXX
855;KH;Cambodia
853;MO;Macau;XXXX XXXX
852;HK;Hong Kong;X XXX XXXX
850;KP;North Korea
692;MH;Marshall Islands
691;FM;Micronesia
690;TK;Tokelau
689;PF;French Polynesia
688;TV;Tuvalu
687;NC;New Caledonia
686;KI;Kiribati
685;WS;Samoa
683;NU;Niue
682;CK;Cook Islands
681;WF;Wallis & Futuna
680;PW;Palau
679;FJ;Fiji
678;VU;Vanuatu
677;SB;Solomon Islands
676;TO;Tonga
675;PG;Papua New Guinea
674;NR;Nauru
673;BN;Brunei Darussalam;XXX XXXX
672;NF;Norfolk Island
670;TL;Timor-Leste
599;BQ;Bonaire, Sint Eustatius & Saba
599;CW;Curaçao
598;UY;Uruguay;X XXX XXXX
597;SR;Suriname;XXX XXXX
596;MQ;Martinique
595;PY;Paraguay;XXX XXX XXX
594;GF;French Guiana
593;EC;Ecuador;XX XXX XXXX
592;GY;Guyana
591;BO;Bolivia;X XXX XXXX
590;GP;Guadeloupe;XXX XX XX XX
509;HT;Haiti
508;PM;Saint Pierre & Miquelon
507;PA;Panama;XXXX XXXX
506;CR;Costa Rica;XXXX XXXX
505;NI;Nicaragua;XXXX XXXX
504;HN;Honduras;XXXX XXXX
503;SV;El Salvador;XXXX XXXX
502;GT;Guatemala;X XXX XXXX
501;BZ;Belize
500;FK;Falkland Islands
423;LI;Liechtenstein
421;SK;Slovakia;XXX XXX XXX
420;CZ;Czech Republic;XXX XXX XXX
389;MK;Macedonia;XX XXX XXX
387;BA;Bosnia & Herzegovina;XX XXX XXX
386;SI;Slovenia;XX XXX XXX
385;HR;Croatia
382;ME;Montenegro
381;RS;Serbia;XX XXX XXXX
380;UA;Ukraine;XX XXX XX XX
378;SM;San Marino;XXX XXX XXXX
377;MC;Monaco;XXXX XXXX
376;AD;Andorra;XX XX XX
375;BY;Belarus;XX XXX XXXX
374;AM;Armenia;XX XXX XXX
373;MD;Moldova;XX XXX XXX
372;EE;Estonia
371;LV;Latvia;XXX XXXXX
370;LT;Lithuania;XXX XXXXX
359;BG;Bulgaria
358;FI;Finland
357;CY;Cyprus;XXXX XXXX
356;MT;Malta;XX XX XX XX
355;AL;Albania;XX XXX XXXX
354;IS;Iceland;XXX XXXX
353;IE;Ireland;XX XXX XXXX
352;LU;Luxembourg
351;PT;Portugal;X XXXX XXXX
350;GI;Gibraltar;XXXX XXXX
299;GL;Greenland;XXX XXX
298;FO;Faroe Islands;XXX XXX
297;AW;Aruba;XXX XXXX
291;ER;Eritrea;X XXX XXX
290;SH;Saint Helena;XX XXX
269;KM;Comoros;XXX XXXX
268;SZ;Swaziland;XXXX XXXX
267;BW;Botswana;XX XXX XXX
266;LS;Lesotho;XX XXX XXX
265;MW;Malawi;77 XXX XXXX
264;NA;Namibia;XX XXX XXXX
263;ZW;Zimbabwe;XX XXX XXXX
262;RE;Réunion;XXX XXX XXX
261;MG;Madagascar;XX XX XXX XX
260;ZM;Zambia;XX XXX XXXX
258;MZ;Mozambique;XX XXX XXXX
257;BI;Burundi;XX XX XXXX
256;UG;Uganda;XX XXX XXXX
255;TZ;Tanzania;XX XXX XXXX
254;KE;Kenya;XXX XXX XXX
253;DJ;Djibouti;XX XX XX XX
252;SO;Somalia;XX XXX XXX
251;ET;Ethiopia;XX XXX XXXX
250;RW;Rwanda;XXX XXX XXX
249;SD;Sudan;XX XXX XXXX
248;SC;Seychelles;X XX XX XX
247;SH;Saint Helena;XXXX
246;IO;Diego Garcia;XXX XXXX
245;GW;Guinea-Bissau;XXX XXXX
244;AO;Angola;XXX XXX XXX
243;CD;Congo (Dem. Rep.);XX XXX XXXX
242;CG;Congo (Rep.);XX XXX XXXX
241;GA;Gabon;X XX XX XX
240;GQ;Equatorial Guinea;XXX XXX XXX
239;ST;São Tomé & Príncipe;XX XXXXX
238;CV;Cape Verde;XXX XXXX
237;CM;Cameroon;XXXX XXXX
236;CF;Central African Rep.;XX XX XX XX
235;TD;Chad;XX XX XX XX
234;NG;Nigeria
233;GH;Ghana
232;SL;Sierra Leone;XX XXX XXX
231;LR;Liberia
230;MU;Mauritius
229;BJ;Benin;XX XXX XXX
228;TG;Togo;XX XXX XXX
227;NE;Niger;XX XX XX XX
226;BF;Burkina Faso;XX XX XX XX
225;CI;Côte d`Ivoire;XX XXX XXX
224;GN;Guinea;XXX XXX XXX
223;ML;Mali;XXXX XXXX
222;MR;Mauritania;XXXX XXXX
221;SN;Senegal;XX XXX XXXX
220;GM;Gambia;XXX XXXX
218;LY;Libya;XX XXX XXXX
216;TN;Tunisia;XX XXX XXX
213;DZ;Algeria;XXX XX XX XX
212;MA;Morocco;XX XXX XXXX
211;SS;South Sudan;XX XXX XXXX
98;IR;Iran;XXX XXX XXXX
95;MM;Myanmar
94;LK;Sri Lanka;XX XXX XXXX
93;AF;Afghanistan;XXX XXX XXX
92;PK;Pakistan;XXX XXX XXXX
91;IN;India;XXXXX XXXXX
90;TR;Turkey;XXX XXX XXXX
86;CN;China;XXX XXXX XXXX
84;VN;Vietnam
82;KR;South Korea
81;JP;Japan;XX XXXX XXXX
66;TH;Thailand;X XXXX XXXX
65;SG;Singapore;XXXX XXXX
64;NZ;New Zealand
63;PH;Philippines;XXX XXX XXXX
62;ID;Indonesia
61;AU;Australia;XXX XXX XXX
60;MY;Malaysia
58;VE;Venezuela;XXX XXX XXXX
57;CO;Colombia;XXX XXX XXXX
56;CL;Chile;X XXXX XXXX
55;BR;Brazil;XX XXXXX XXXX
54;AR;Argentina
53;CU;Cuba;XXXX XXXX
52;MX;Mexico
51;PE;Peru;XXX XXX XXX
49;DE;Germany
48;PL;Poland;XX XXX XXXX
47;NO;Norway;XXXX XXXX
46;SE;Sweden;XX XXX XXXX
45;DK;Denmark;XXXX XXXX
44;GB;United Kingdom;XXXX XXXXXX
43;AT;Austria
42;YL;Y-land
41;CH;Switzerland;XX XXX XXXX
40;RO;Romania;XXX XXX XXX
39;IT;Italy
36;HU;Hungary;XXX XXX XXX
34;ES;Spain;XXX XXX XXX
33;FR;France;X XX XX XX XX
32;BE;Belgium;XXX XX XX XX
31;NL;Netherlands;X XX XX XX XX
30;GR;Greece;XXX XXX XXXX
27;ZA;South Africa;XX XXX XXXX
20;EG;Egypt;XX XXXX XXXX
7;KZ;Kazakhstan;XXX XXX XX XX
7;RU;Russian Federation;XXX XXX XXXX
1;PR;Puerto Rico;XXX XXX XXXX
1;DO;Dominican Rep.;XXX XXX XXXX
1;CA;Canada;XXX XXX XXXX
1;US;USA;XXX XXX XXXX
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -1,24 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AppStartReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
ApplicationLoader.startPushService();
}
});
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -18,65 +33,46 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import com.b44t.ui.Components.ForegroundDetector;
import com.b44t.ui.SettingsAdvActivity;
import java.io.File;
public class ApplicationLoader extends Application {
private static PendingIntent pendingIntent;
private static Drawable cachedWallpaper;
private static int selectedColor;
private static boolean isCustomTheme;
private static final Object sync = new Object();
private static int serviceMessageColor;
private static int serviceSelectedMessageColor;
public static volatile Context applicationContext;
public static volatile Handler applicationHandler;
private static volatile boolean applicationInited = false;
public static volatile boolean isScreenOn = false;
public static volatile boolean mainInterfacePaused = true;
public static boolean isCustomTheme() {
return isCustomTheme;
}
public static PowerManager.WakeLock backendWakeLock = null;
public static PowerManager.WakeLock wakeupWakeLock = null;
private static PowerManager.WakeLock stayAwakeWakeLock = null;
public static int getSelectedColor() {
return selectedColor;
}
public static int fontSize;
public static void reloadWallpaper() {
cachedWallpaper = null;
serviceMessageColor = 0;
ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().remove("serviceMessageColor").commit();
loadWallpaper();
}
private static void calcBackgroundColor() {
int result[] = AndroidUtilities.calcDrawableColor(cachedWallpaper);
serviceMessageColor = result[0];
serviceSelectedMessageColor = result[1];
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
preferences.edit().putInt("serviceMessageColor", serviceMessageColor).putInt("serviceSelectedMessageColor", serviceSelectedMessageColor).commit();
}
public static int getServiceMessageColor() {
return serviceMessageColor;
}
public static int getServiceSelectedMessageColor() {
return serviceSelectedMessageColor;
return 0x44000000; // this color is used as a background for date headlines, empty chat hints and in the drawer
}
public static void loadWallpaper() {
@@ -92,20 +88,15 @@ public class ApplicationLoader extends Application {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
int selectedBackground = preferences.getInt("selectedBackground", 1000001);
selectedColor = preferences.getInt("selectedColor", 0);
serviceMessageColor = preferences.getInt("serviceMessageColor", 0);
serviceSelectedMessageColor = preferences.getInt("serviceSelectedMessageColor", 0);
if (selectedColor == 0) {
if (selectedBackground == 1000001) {
cachedWallpaper = applicationContext.getResources().getDrawable(R.drawable.background_hd);
isCustomTheme = false;
} else {
File toFile = new File(getFilesDirFixed(), "wallpaper.jpg");
if (toFile.exists()) {
cachedWallpaper = Drawable.createFromPath(toFile.getAbsolutePath());
isCustomTheme = true;
} else {
cachedWallpaper = applicationContext.getResources().getDrawable(R.drawable.background_hd);
isCustomTheme = false;
}
}
}
@@ -118,9 +109,6 @@ public class ApplicationLoader extends Application {
}
cachedWallpaper = new ColorDrawable(selectedColor);
}
if (serviceMessageColor == 0) {
calcBackgroundColor();
}
}
}
});
@@ -145,25 +133,56 @@ public class ApplicationLoader extends Application {
path.mkdirs();
return path;
} catch (Exception e) {
FileLog.e("messenger", e);
}
return new File("/data/data/com.b44t.messenger/files"); // EDIT BY MR
return new File("/data/data/com.b44t.messenger/files");
}
public static void postInitApplication() {
if (applicationInited) {
return;
@Override
public void onCreate() {
super.onCreate();
applicationContext = getApplicationContext(); // should be set very first as it may be needed eg. for logging
MrMailbox.log_i("DeltaChat", "*************** ApplicationLoader.onCreate() ***************");
System.loadLibrary("messenger.1");
new ForegroundDetector(this);
applicationHandler = new Handler(applicationContext.getMainLooper());
// create wake locks
try {
PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
backendWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backendWakeLock" /*any name*/);
// bakendWakeLock _is_ reference counted by the backend (every acquire() has a release())
wakeupWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wakeupWakeLock" /*any name*/);
wakeupWakeLock.setReferenceCounted(false);
stayAwakeWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "stayAwakeWakeLock" /*any name*/);
stayAwakeWakeLock.setReferenceCounted(false);
} catch (Exception e) {
Log.e("DeltaChat", "Cannot acquire wakeLock");
}
applicationInited = true;
//convertConfig();
// create a MrMailbox object; as android stops the App by just killing it, we do never call MrMailboxUnref()
// however, we may want to to have a look at onPause() eg. of activities (eg. for flushing data, if needed)
MrMailbox.MrCallback(0, 0, 0); // do not remove this call; this makes sure, the function is not removed from build or warnings are printed!
MrMailbox.init();
// start keep-alive service that restarts the app as soon it is terminated
// (this is done by just marking the service as START_STICKY which recreates the service as
// it goes away which also inititialized the app indirectly by calling this function)
applicationContext.startService(new Intent(applicationContext, KeepAliveService.class));
// init locale
try {
LocaleController.getInstance();
} catch (Exception e) {
e.printStackTrace();
}
// track screen on/ff
try {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -176,148 +195,38 @@ public class ApplicationLoader extends Application {
try {
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
isScreenOn = pm.isScreenOn();
FileLog.e("messenger", "screen state = " + isScreenOn);
//Log.i("DeltaChat", "screen state = " + isScreenOn);
} catch (Exception e) {
FileLog.e("messenger", e);
}
UserConfig.loadConfig();
String deviceModel;
String langCode;
String appVersion;
String systemVersion;
String configPath = getFilesDirFixed().toString();
try {
langCode = LocaleController.getLocaleStringIso639();
deviceModel = Build.MANUFACTURER + Build.MODEL;
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
appVersion = pInfo.versionName + " (" + pInfo.versionCode + ")";
systemVersion = "SDK " + Build.VERSION.SDK_INT;
} catch (Exception e) {
langCode = "en";
deviceModel = "Android unknown";
appVersion = "App version unknown";
systemVersion = "SDK " + Build.VERSION.SDK_INT;
}
if (langCode.trim().length() == 0) {
langCode = "en";
}
if (deviceModel.trim().length() == 0) {
deviceModel = "Android unknown";
}
if (appVersion.trim().length() == 0) {
appVersion = "App version unknown";
}
if (systemVersion.trim().length() == 0) {
systemVersion = "SDK Unknown";
}
// create a timer that wakes up the CPU from time to time
TimerReceiver.scheduleNextAlarm();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
boolean enablePushConnection = preferences.getBoolean("pushConnection", true);
if( preferences.getInt("notify2_"+MrChat.MR_CHAT_ID_DEADDROP, 666)==666 ) {
// make sure, the notifications for the "deaddrop" dialog are muted by default
SharedPreferences.Editor editor = preferences.edit();
// make sure, the notifications for the "deaddrop" dialog are muted by default
SharedPreferences notificationPreferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
if( notificationPreferences.getInt("notify2_"+MrChat.MR_CHAT_ID_DEADDROP, 666)==666 ) {
SharedPreferences.Editor editor = notificationPreferences.edit();
editor.putInt("notify2_"+MrChat.MR_CHAT_ID_DEADDROP, 2);
editor.commit();
editor.apply();
}
MessagesController.getInstance();
ConnectionsManager.getInstance().init(deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId(), enablePushConnection);
if (UserConfig.getCurrentUser() != null) {
//MessagesController.getInstance().putUser(UserConfig.getCurrentUser(), true);
SendMessagesHelper.getInstance().checkUnsentMessages();
}
ApplicationLoader app = (ApplicationLoader)ApplicationLoader.applicationContext;
FileLog.e("messenger", "app initied");
//ContactsController.getInstance().checkAppAccount();
MediaController.getInstance();
// EDIT BY MR - open my sqlite file (you can inspect the file eg. with "Tools / Android Device Monitor / File Explorer")
// open() sqlite file (you can inspect the file eg. with "Tools / Android Device Monitor / File Explorer")
// open() should be called before MessagesController.getInstance() as this also initilizes directories based upon getBlobdir().
File dbfile = new File(getFilesDirFixed(), "messenger.db");
MrMailbox.open(dbfile.getAbsolutePath(), "");
MrMailbox.connect();
}
@Override
public void onCreate() {
super.onCreate();
applicationContext = getApplicationContext();
NativeLoader.initNativeLibs(ApplicationLoader.applicationContext);
//ConnectionsManager.native_setJava(Build.VERSION.SDK_INT == 14 || Build.VERSION.SDK_INT == 15);
new ForegroundDetector(this);
// EDIT BY MR - create a MrMailbox object; as android stops the App by just killing it, we do never call MrMailboxUnref()
// however, we may want to to have a look at onPause() eg. of activities (eg. for flushing data, if needed)
MrMailbox.MrCallback(0, 0, 0); // do not remove this call; this makes sure, the function is not removed from build or warnings are printed!
MrMailbox.init();
MrMailbox.MrStockAddStr(1, LocaleController.getString("NoMessages", R.string.NoMessages));
MrMailbox.MrStockAddStr(2, LocaleController.getString("FromSelf", R.string.FromSelf));
MrMailbox.MrStockAddStr(3, LocaleController.getString("Draft", R.string.Draft));
MrMailbox.MrStockAddStr(4, LocaleController.getString("MemberSg", R.string.MemberSg));
MrMailbox.MrStockAddStr(5, LocaleController.getString("MemberPl", R.string.MemberPl));
MrMailbox.MrStockAddStr(6, LocaleController.getString("ContactSg", R.string.ContactSg));
MrMailbox.MrStockAddStr(7, LocaleController.getString("ContactPl", R.string.ContactPl));
MrMailbox.MrStockAddStr(8, LocaleController.getString("Deaddrop", R.string.Deaddrop));
MrMailbox.MrStockAddStr(9, LocaleController.getString("AttachPhoto", R.string.AttachPhoto));
MrMailbox.MrStockAddStr(10, LocaleController.getString("AttachVideo", R.string.AttachVideo));
MrMailbox.MrStockAddStr(11, LocaleController.getString("AttachAudio", R.string.AttachAudio));
MrMailbox.MrStockAddStr(12, LocaleController.getString("AttachDocument", R.string.AttachDocument));
MrMailbox.MrStockAddStr(13, LocaleController.getString("DefaultStatusText", R.string.DefaultStatusText));
MrMailbox.MrStockAddStr(14, LocaleController.getString("SubjectPrefix", R.string.SubjectPrefix));
applicationHandler = new Handler(applicationContext.getMainLooper());
startPushService();
}
/*public static void sendRegIdToBackend(final String token) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
UserConfig.pushString = token;
UserConfig.registeredForPush = false;
UserConfig.saveConfig(false);
if (UserConfig.getClientUserId() != 0) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().registerForPush(token);
}
});
}
}
});
}*/
public static void startPushService() {
SharedPreferences preferences = applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE);
if (preferences.getBoolean("pushService", true)) {
AlarmManager am = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(applicationContext, ApplicationLoader.class);
pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, i, 0);
am.cancel(pendingIntent);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, pendingIntent);
applicationContext.startService(new Intent(applicationContext, NotificationsService.class));
} else {
stopPushService();
MrMailbox.open(dbfile.getAbsolutePath());
if( MrMailbox.isConfigured()!=0 ) {
MrMailbox.connect();
}
}
public static void stopPushService() {
applicationContext.stopService(new Intent(applicationContext, NotificationsService.class));
// create other default objects
SharedPreferences mainPreferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
fontSize = mainPreferences.getInt("msg_font_size", SettingsAdvActivity.defMsgFontSize());
PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0);
AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pintent);
alarm.cancel(pendingIntent);
ImageLoader.getInstance();
MediaController.getInstance();
}
@Override
@@ -330,4 +239,27 @@ public class ApplicationLoader extends Application {
e.printStackTrace();
}
}
private static int lastClassGuid = 1;
public static int generateClassGuid() {
return lastClassGuid++;
}
public static boolean isNetworkOnline() {
try {
ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
}
} catch (Exception e) {
}
return false;
}
public static void stayAwakeForAMoment()
{
stayAwakeWakeLock.acquire(1*60*1000); // 1 Minute to wait for "after chat" messages, after that, we sleep most time, see wakeupWakeLock
}
}
@@ -0,0 +1,85 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
public class AttachmentsContentProvider extends ContentProvider {
/* We save all attachments in our private files-directory
that cannot be read by other apps.
So starting, when starting an Intent for viewing (eg. openForView()), we cannot use the paths.
Instead, we give a content://-url that results in calls to this class.
(An alternative would be to copy files to view to a public directory, however, this would
lead to duplicate data.
Another alterntive would be to write all attachments to a public directory, however, this
may lead to security problems as files are system-wide-readable and would also cause problems
if the user or another app deletes these files) */
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File privateFile = new File(MrMailbox.getBlobdir(), uri.getPath());
return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
return 0;
}
@Override
public String getType(Uri arg0) {
return null;
}
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
return null;
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
return null;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
return 0;
}
}
@@ -1,97 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
public class AuthenticatorService extends Service {
private static class Authenticator extends AbstractAccountAuthenticator {
private final Context context;
public Authenticator(Context context) {
super(context);
this.context = context;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options)
throws NetworkErrorException {
return null;
}
@Override
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {
return super.getAccountRemovalAllowed(response, account);
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response,
Account account, String[] features)
throws NetworkErrorException {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
throws NetworkErrorException {
return null;
}
}
private static Authenticator authenticator = null;
protected Authenticator getAuthenticator() {
if (authenticator == null) {
authenticator = new Authenticator(this);
}
return authenticator;
}
@Override
public IBinder onBind(Intent intent) {
if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
return getAuthenticator().getIBinder();
} else {
return null;
}
}
}
@@ -1,27 +1,44 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class AutoMessageHeardReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
long dialog_id = intent.getLongExtra("dialog_id", 0);
int max_id = intent.getIntExtra("max_id", 0);
if (dialog_id == 0 || max_id == 0) {
return;
}
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
MrMailbox.markseenChat((int)dialog_id);
NotificationsController.getInstance().removeSeenMessages();
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -13,12 +28,13 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.RemoteInput;
import android.util.Log;
public class AutoMessageReplyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput == null) {
return;
@@ -32,7 +48,8 @@ public class AutoMessageReplyReceiver extends BroadcastReceiver {
if (dialog_id == 0 || max_id == 0) {
return;
}
SendMessagesHelper.getInstance().sendMessageText(text.toString(), dialog_id, null, null, true, null, null);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
SendMessagesHelper.getInstance().sendMessageText(text.toString(), dialog_id, null);
MrMailbox.markseenChat((int)dialog_id);
NotificationsController.getInstance().removeSeenMessages();
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -0,0 +1,37 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootCompletedReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
MrMailbox.log_i("DeltaChat", "*** BootCompletedReceiver.onReceive()");
// there's nothing more to do here as all initialisation stuff is already done in
// ApplicationLoader.onCreate() which is called before this broadcast is sended.
}
}
@@ -1,13 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
public class BuildVars {
public static boolean DEBUG_VERSION = false;
}
@@ -1,30 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
public class ChatObject {
public static final int CHAT_TYPE_CHAT = 0;
public static boolean isNotInChat(TLRPC.Chat chat) {
return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat.left || chat.kicked || chat.deactivated;
}
public static boolean isChannel(TLRPC.Chat chat) {
return false;
}
public static boolean isChannel(int chatId) {
return false;
}
public static boolean canWriteToChat(TLRPC.Chat chat) {
return true;
}
}
@@ -1,82 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.system.Os;
import android.system.StructStat;
import java.io.File;
import java.util.HashMap;
public class ClearCacheService extends IntentService {
public ClearCacheService() {
super("ClearCacheService");
}
@Override
protected void onHandleIntent(Intent intent) {
ApplicationLoader.postInitApplication();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
final int keepMedia = preferences.getInt("keep_media", 2);
if (keepMedia == 2) {
return;
}
Utilities.globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
long currentTime = System.currentTimeMillis();
long diff = 60 * 60 * 1000 * 24 * (keepMedia == 0 ? 7 : 30);
final HashMap<Integer, File> paths = ImageLoader.getInstance().createMediaPaths();
for (HashMap.Entry<Integer, File> entry : paths.entrySet()) {
if (entry.getKey() == FileLoader.MEDIA_DIR_CACHE) {
continue;
}
try {
File[] array = entry.getValue().listFiles();
if (array != null) {
for (int b = 0; b < array.length; b++) {
File f = array[b];
if (f.isFile()) {
if (f.getName().equals(".nomedia")) {
continue;
}
if (Build.VERSION.SDK_INT >= 21) {
try {
StructStat stat = Os.stat(f.getPath());
if (stat.st_atime != 0) {
if (stat.st_atime + diff < currentTime) {
f.delete();
}
} else if (stat.st_mtime + diff < currentTime) {
f.delete();
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
} else if (f.lastModified() + diff < currentTime) {
f.delete();
}
}
}
}
} catch (Throwable e) {
FileLog.e("messenger", e);
}
}
}
});
}
}
@@ -1,170 +0,0 @@
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PowerManager;
public class ConnectionsManager {
public final static int RequestFlagFailOnServerErrors = 2;
public final static int ConnectionStateConnecting = 1;
public final static int ConnectionStateWaitingForNetwork = 2;
public final static int ConnectionStateConnected = 3;
public final static int ConnectionStateUpdating = 4;
private long lastPauseTime = System.currentTimeMillis();
private boolean appPaused = true;
private int lastClassGuid = 1;
private PowerManager.WakeLock wakeLock = null;
private static volatile ConnectionsManager Instance = null;
public static ConnectionsManager getInstance() {
ConnectionsManager localInstance = Instance;
if (localInstance == null) {
synchronized (ConnectionsManager.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new ConnectionsManager();
}
}
}
return localInstance;
}
public ConnectionsManager() {
try {
PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock");
wakeLock.setReferenceCounted(false);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
public int getCurrentTime() {
return MrMailbox.getCurrentTime();
}
public void cancelRequest(int token, boolean notifyServer) {
//native_cancelRequest(token, notifyServer);
}
public void cleanup() {
//native_cleanUp();
}
public int getConnectionState() {
return ConnectionStateWaitingForNetwork; // EDIT BY MR - we're always disconnected from the view of the caller
/* EDIT BY MR
if (connectionState == ConnectionStateConnected && isUpdating) {
return ConnectionStateUpdating;
}
return connectionState;
*/
}
public void setPushConnectionEnabled(boolean value) {
//native_setPushConnectionEnabled(value);
}
public void init(String deviceModel, String systemVersion, String appVersion, String langCode, String configPath, String logPath, int userId, boolean enablePushConnection) {
//native_init(version, layer, apiId, deviceModel, systemVersion, appVersion, langCode, configPath, logPath, userId, enablePushConnection);
//checkConnection();
BroadcastReceiver networkStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//checkConnection();
}
};
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
ApplicationLoader.applicationContext.registerReceiver(networkStateReceiver, filter);
}
public void resumeNetworkMaybe() {
//native_resumeNetwork(true);
}
public void setAppPaused(final boolean value, final boolean byScreenState) {
if (!byScreenState) {
appPaused = value;
FileLog.d("messenger", "app paused = " + value);
}
if (value) {
if (lastPauseTime == 0) {
lastPauseTime = System.currentTimeMillis();
}
//native_pauseNetwork();
} else {
if (appPaused) {
return;
}
FileLog.e("messenger", "reset app pause time");
/*if (lastPauseTime != 0 && System.currentTimeMillis() - lastPauseTime > 5000) {
ContactsController.getInstance().checkContacts();
}*/
lastPauseTime = 0;
//native_resumeNetwork(false);
}
}
public int generateClassGuid() {
return lastClassGuid++;
}
public static boolean isRoaming() {
try {
ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null) {
return netInfo.isRoaming();
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return false;
}
public static boolean isConnectedToWiFi() {
try {
ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (netInfo != null && netInfo.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return false;
}
public static boolean isNetworkOnline() {
try {
ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && (netInfo.isConnectedOrConnecting() || netInfo.isAvailable())) {
return true;
}
netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
} else {
netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
}
} catch (Exception e) {
FileLog.e("messenger", e);
return true;
}
return false;
}
}
@@ -1,51 +1,71 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
*******************************************************************************
*
* File: ContactsController.java
* Authors: Björn Petersen
*
******************************************************************************/
package com.b44t.messenger;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import com.b44t.ui.Components.AvatarDrawable;
import java.io.InputStream;
import java.util.HashMap;
public class ContactsController {
static ContentResolver s_cr;
private static final String TAG = "ContactsController";
public static class Contact {
public String name;
public String email;
}
private String[] projectionNames = {
private final static String[] projectionNames = {
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Email.ADDRESS
};
private static volatile ContactsController Instance = null;
public static ContactsController getInstance() {
ContactsController localInstance = Instance;
if (localInstance == null) {
synchronized (ContactsController.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new ContactsController();
}
}
}
return localInstance;
}
public ContactsController() {
}
public String readContactsFromPhoneBook() {
public static String readContactsFromPhoneBook() {
HashMap<String, String> contactsMap = new HashMap<String, String>();
String allContacts = "";
try {
@@ -72,12 +92,12 @@ public class ContactsController {
pCur.close();
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return allContacts;
}
private boolean hasContactsPermission() {
private static boolean hasContactsPermission() {
if (Build.VERSION.SDK_INT >= 23) {
return ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
}
@@ -89,14 +109,14 @@ public class ContactsController {
return false;
}
} catch (Exception e) {
FileLog.e("messenger", e);
;
} finally {
try {
if (cursor != null) {
cursor.close();
}
} catch (Exception e) {
FileLog.e("messenger", e);
;
}
}
return true;
@@ -134,4 +154,233 @@ public class ContactsController {
}
return result.toString();
}
/* Handle contact images
**********************************************************************************************/
static class AvtCacheEntry {
public Bitmap m_avatarBitmap;
public String m_fallbackName;
public boolean m_needsReload;
AvtCacheEntry(Bitmap avatarBitmap, String fallbackName) {
m_avatarBitmap = avatarBitmap;
m_fallbackName = fallbackName;
m_needsReload = false;
}
}
private final static String[] s_projectionAvatars = new String[]{
ContactsContract.Contacts._ID,
ContactsContract.Contacts.PHOTO_ID,
ContactsContract.CommonDataKinds.Email.ADDRESS
//ContactsContract.CommonDataKinds.Email.DISPLAY_NAME,
};
private static final Object s_sync = new Object();
private static HashMap<String, AvtCacheEntry> s_avtCache = new HashMap<>();
public static void cleanupAvatarCache() {
// to detect changes of the avatar images eg. in the Contacts App,
// this function should be called whenever the App goes to background or back to foreground.
// instead of emptying the cache, we force a reloading (looks smarter - most times, the avatars do not change)
synchronized (s_sync) {
for (AvtCacheEntry cacheEntry : s_avtCache.values()) {
cacheEntry.m_needsReload = true;
}
}
}
public static void setupAvatar(final View avtView,
final ImageReceiver avtImageReceiver,
final AvatarDrawable avtDrawable,
MrContact mrContact,
MrChat mrChat)
{
// get email/name to search avatar image for
String tempEmail = null;
String tempName = "";
if (mrContact != null) {
tempEmail = mrContact.getAddr();
tempName = mrContact.getDisplayName();
} else if (mrChat != null) {
tempName = mrChat.getName();
if (mrChat.getType() == MrChat.MR_CHAT_NORMAL) {
int[] contact_ids = MrMailbox.getChatContacts(mrChat.getId());
if (contact_ids.length == 1) {
MrContact mrc = MrMailbox.getContact(contact_ids[0]);
tempEmail = mrc.getAddr();
tempName = mrc.getDisplayName();
}
}
}
setupAvatarByStrings(avtView, avtImageReceiver, avtDrawable, tempEmail, tempName);
}
public static void setupAvatarByStrings(final View avtView,
final ImageReceiver avtImageReceiver,
final AvatarDrawable avtDrawable,
String tempEmail,
String tempName)
{
if( tempEmail == null ) {
tempEmail = "fallback:" + tempName;
}
final String email = tempEmail;
final String fallbackName = tempName;
// bind e-mail+name address to view object to detect overwrites and discard loading old images (may happen on fast scrolling)
// moreover, check if the avatar is in cache
AvtCacheEntry cacheEntry;
synchronized (s_sync) {
avtImageReceiver.m_userDataUnique = email+fallbackName;
cacheEntry = s_avtCache.get(email+fallbackName);
}
if( cacheEntry != null )
{
// can use avatar from cache, very fine
if (cacheEntry.m_avatarBitmap != null) {
avtImageReceiver.setImageBitmap(cacheEntry.m_avatarBitmap);
} else {
avtDrawable.setInfoByName(cacheEntry.m_fallbackName);
avtImageReceiver.setImage(null, "50_50", avtDrawable, null, false);
}
}
else
{
// avatar is not in cache, empty the image (may be the bitmap of another use as we re-use the objects)
avtImageReceiver.setImage(null, "50_50", null, null, false);
}
if( cacheEntry==null || cacheEntry.m_needsReload )
{
// avatar is not in cache or needs reloading:
// load avatar in a working thread (when loaded, we'll add it to cache and invalidate back in the GUI thread)
Utilities.searchQueue.postRunnable(new Runnable() {
@Override
public void run() {
// is the avatar still desired?
synchronized (s_sync) {
if (!avtImageReceiver.m_userDataUnique.equals(email+fallbackName)) {
return;
}
}
// try to get avatar image from the address book
Bitmap tempBitmap = null;
if (!email.startsWith("fallback:")) {
try {
if (s_cr == null) {
s_cr = ApplicationLoader.applicationContext.getContentResolver();
}
Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(email));
Cursor pCur = s_cr.query(uri, s_projectionAvatars, null, null, null);
if (pCur != null) {
if (pCur.getCount() > 0) {
while (pCur.moveToNext()) {
int contact_id = pCur.getInt(0);
int photo_id = pCur.getInt(1);
String addr = pCur.getString(2);
if (addr.equalsIgnoreCase(email) && contact_id > 0 && photo_id > 0) {
Bitmap tempBitmap2 = loadContactPhoto(s_cr, contact_id, photo_id);
if (tempBitmap2 != null) {
tempBitmap = createRoundBitmap(tempBitmap2);
}
break;
}
}
}
pCur.close();
}
} catch (Exception e) {
;
}
}
final Bitmap photoBitmap = tempBitmap;
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
// is the avatar still desired?
synchronized (s_sync) {
if (!avtImageReceiver.m_userDataUnique.equals(email+fallbackName)) {
return;
}
}
if (photoBitmap != null) {
avtImageReceiver.setImageBitmap(photoBitmap);
} else {
avtDrawable.setInfoByName(fallbackName);
avtImageReceiver.setImage(null, "50_50", avtDrawable, null, false);
}
avtView.invalidate();
synchronized (s_sync) {
s_avtCache.put(email+fallbackName, new AvtCacheEntry(photoBitmap, fallbackName));
}
}
});
}
});
}
}
// from http://stackoverflow.com/questions/2383580/how-do-i-load-a-contact-photo
public static Bitmap loadContactPhoto(ContentResolver cr, long contact_id, long photo_id)
{
// first try using photo_id
byte[] photoBytes = null;
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, photo_id);
Cursor c = cr.query(photoUri, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
if( c != null ) {
try {
if (c.moveToFirst()) {
photoBytes = c.getBlob(0);
}
} catch (Exception e) {
;
} finally {
c.close();
}
}
if (photoBytes != null) {
return BitmapFactory.decodeByteArray(photoBytes, 0, photoBytes.length);
}
// second try using contact_id
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contact_id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input != null) {
return BitmapFactory.decodeStream(input);
}
return null;
}
private static Paint roundPaint;
private static RectF bitmapRect;
private static Bitmap createRoundBitmap(Bitmap bitmap) {
try {
Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
result.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(result);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
if (roundPaint == null) {
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapRect = new RectF();
}
roundPaint.setShader(shader);
bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawRoundRect(bitmapRect, bitmap.getWidth(), bitmap.getHeight(), roundPaint);
return result;
} catch (Throwable e) {
;
}
return null;
}
}
@@ -1,63 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.accounts.Account;
import android.accounts.OperationCanceledException;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.os.IBinder;
public class ContactsSyncAdapterService extends Service {
private static SyncAdapterImpl sSyncAdapter = null;
public ContactsSyncAdapterService() {
super();
}
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
private Context mContext;
public SyncAdapterImpl(Context context) {
super(context, true);
mContext = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
try {
ContactsSyncAdapterService.performSync(mContext, account, extras, authority, provider, syncResult);
} catch (OperationCanceledException e) {
FileLog.e("messenger", e);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return getSyncAdapter().getSyncAdapterBinder();
}
private SyncAdapterImpl getSyncAdapter() {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapterImpl(this);
}
return sSyncAdapter;
}
private static void performSync(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
throws OperationCanceledException {
FileLog.d("messenger", "performSync: " + account.toString());
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -33,7 +48,7 @@ public class DispatchQueue extends Thread {
handler.sendMessageDelayed(msg, delay);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
*/
@@ -43,7 +58,7 @@ public class DispatchQueue extends Thread {
syncLatch.await();
handler.removeCallbacks(runnable);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
@@ -60,7 +75,7 @@ public class DispatchQueue extends Thread {
handler.postDelayed(runnable, delay);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
@@ -70,7 +85,7 @@ public class DispatchQueue extends Thread {
syncLatch.await();
handler.removeCallbacksAndMessages(null);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
*/
@@ -1,15 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
public class DownloadObject {
public TLObject object;
public int type;
public long id;
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -102,7 +117,7 @@ public class Emoji {
}
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
@@ -143,7 +158,7 @@ public class Emoji {
}
});
} catch (Throwable x) {
FileLog.e("messenger", "Error loading emoji", x);
//Log.i("DeltaChat", "Error loading emoji", x);
}
}
@@ -194,7 +209,7 @@ public class Emoji {
public static EmojiDrawable getEmojiDrawable(CharSequence code) {
DrawableInfo info = rects.get(code);
if (info == null) {
FileLog.e("messenger", "No drawable for emoji " + code);
//Log.i("DeltaChat", "No drawable for emoji " + code);
return null;
}
EmojiDrawable ed = new EmojiDrawable(info);
@@ -419,7 +434,7 @@ public class Emoji {
// }
// }
// } catch (Exception e) {
// FileLog.e("messenger", e);
//
// return cs;
// }
return s;
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -1,428 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import java.io.RandomAccessFile;
import java.io.File;
import java.util.ArrayList;
public class FileLoadOperation {
private static class RequestInfo {
private int requestToken;
private int offset;
}
private final static int stateIdle = 0;
private final static int stateDownloading = 1;
private final static int stateFailed = 2;
private final static int stateFinished = 3;
private final static int downloadChunkSize = 1024 * 32;
private final static int downloadChunkSizeBig = 1024 * 128;
private final static int maxDownloadRequests = 4;
private final static int maxDownloadRequestsBig = 2;
private final static int bigFileSizeFrom = 1024 * 1024;
private int datacenter_id;
private TLRPC.InputFileLocation location;
private volatile int state = stateIdle;
private int downloadedBytes;
private int totalBytesCount;
private int bytesCountPadding;
private FileLoadOperationDelegate delegate;
private byte[] key;
private byte[] iv;
private int currentDownloadChunkSize;
private int currentMaxDownloadRequests;
private int requestsCount;
private int renameRetryCount;
private int nextDownloadOffset;
private ArrayList<RequestInfo> requestInfos;
private ArrayList<RequestInfo> delayedRequestInfos;
private File cacheFileTemp;
private File cacheFileFinal;
private File cacheIvTemp;
private String ext;
private RandomAccessFile fileOutputStream;
private RandomAccessFile fiv;
private File storePath;
private File tempPath;
private boolean isForceRequest;
public interface FileLoadOperationDelegate {
void didFinishLoadingFile(FileLoadOperation operation, File finalFile);
void didFailedLoadingFile(FileLoadOperation operation, int state);
void didChangedLoadProgress(FileLoadOperation operation, float progress);
}
public FileLoadOperation(TLRPC.FileLocation photoLocation, String extension, int size) {
/*if (photoLocation instanceof TLRPC.TL_fileEncryptedLocation) {
location = new TLRPC.TL_inputEncryptedFileLocation();
location.id = photoLocation.volume_id;
location.volume_id = photoLocation.volume_id;
location.access_hash = photoLocation.secret;
location.local_id = photoLocation.local_id;
iv = new byte[32];
System.arraycopy(photoLocation.iv, 0, iv, 0, iv.length);
key = photoLocation.key;
datacenter_id = photoLocation.dc_id;
} else*/ if (photoLocation instanceof TLRPC.TL_fileLocation) {
location = new TLRPC.TL_inputFileLocation();
location.volume_id = photoLocation.volume_id;
location.local_id = photoLocation.local_id;
datacenter_id = photoLocation.dc_id;
}
totalBytesCount = size;
ext = extension != null ? extension : "jpg";
}
public FileLoadOperation(TLRPC.Document documentLocation) {
try {
/*if (documentLocation instanceof TLRPC.TL_documentEncrypted) {
location = new TLRPC.TL_inputEncryptedFileLocation();
location.id = documentLocation.id;
location.access_hash = documentLocation.access_hash;
datacenter_id = documentLocation.dc_id;
iv = new byte[32];
System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length);
key = documentLocation.key;
} else*/ if (documentLocation instanceof TLRPC.TL_document) {
location = new TLRPC.TL_inputDocumentFileLocation();
location.id = documentLocation.id;
location.access_hash = documentLocation.access_hash;
datacenter_id = documentLocation.dc_id;
}
totalBytesCount = documentLocation.size;
if (key != null) {
int toAdd = 0;
if (totalBytesCount % 16 != 0) {
bytesCountPadding = 16 - totalBytesCount % 16;
totalBytesCount += bytesCountPadding;
}
}
ext = FileLoader.getDocumentFileName(documentLocation);
int idx;
if (ext == null || (idx = ext.lastIndexOf('.')) == -1) {
ext = "";
} else {
ext = ext.substring(idx);
}
if (ext.length() <= 1) {
if (documentLocation.mime_type != null) {
switch (documentLocation.mime_type) {
case "video/mp4":
ext = ".mp4";
break;
case "audio/ogg":
ext = ".ogg";
break;
default:
ext = "";
break;
}
} else {
ext = "";
}
}
} catch (Exception e) {
FileLog.e("messenger", e);
state = stateFailed;
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
}
}
public void setForceRequest(boolean forceRequest) {
isForceRequest = forceRequest;
}
public boolean isForceRequest() {
return isForceRequest;
}
public void setPaths(File store, File temp) {
storePath = store;
tempPath = temp;
}
public void start() {
if (state != stateIdle) {
return;
}
currentDownloadChunkSize = totalBytesCount >= bigFileSizeFrom ? downloadChunkSizeBig : downloadChunkSize;
currentMaxDownloadRequests = totalBytesCount >= bigFileSizeFrom ? maxDownloadRequestsBig : maxDownloadRequests;
requestInfos = new ArrayList<>(currentMaxDownloadRequests);
delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1);
state = stateDownloading;
if (location == null) {
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
return;
}
String fileNameFinal;
String fileNameTemp;
String fileNameIv = null;
if (location.volume_id != 0 && location.local_id != 0) {
fileNameTemp = location.volume_id + "_" + location.local_id + ".temp";
fileNameFinal = location.volume_id + "_" + location.local_id + "." + ext;
if (key != null) {
fileNameIv = location.volume_id + "_" + location.local_id + ".iv";
}
if (datacenter_id == Integer.MIN_VALUE || location.volume_id == Integer.MIN_VALUE || datacenter_id == 0) {
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
return;
}
} else {
fileNameTemp = datacenter_id + "_" + location.id + ".temp";
fileNameFinal = datacenter_id + "_" + location.id + ext;
if (key != null) {
fileNameIv = datacenter_id + "_" + location.id + ".iv";
}
if (datacenter_id == 0 || location.id == 0) {
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
return;
}
}
cacheFileFinal = new File(storePath, fileNameFinal);
boolean exist = cacheFileFinal.exists();
if (exist && totalBytesCount != 0 && totalBytesCount != cacheFileFinal.length()) {
cacheFileFinal.delete();
}
if (!cacheFileFinal.exists()) {
cacheFileTemp = new File(tempPath, fileNameTemp);
if (cacheFileTemp.exists()) {
downloadedBytes = (int) cacheFileTemp.length();
nextDownloadOffset = downloadedBytes = downloadedBytes / currentDownloadChunkSize * currentDownloadChunkSize;
}
if (BuildVars.DEBUG_VERSION) {
FileLog.d("messenger", "start loading file to temp = " + cacheFileTemp + " final = " + cacheFileFinal);
}
if (fileNameIv != null) {
cacheIvTemp = new File(tempPath, fileNameIv);
try {
fiv = new RandomAccessFile(cacheIvTemp, "rws");
long len = cacheIvTemp.length();
if (len > 0 && len % 32 == 0) {
fiv.read(iv, 0, 32);
} else {
downloadedBytes = 0;
}
} catch (Exception e) {
FileLog.e("messenger", e);
downloadedBytes = 0;
}
}
try {
fileOutputStream = new RandomAccessFile(cacheFileTemp, "rws");
if (downloadedBytes != 0) {
fileOutputStream.seek(downloadedBytes);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
if (fileOutputStream == null) {
cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
});
return;
}
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (totalBytesCount != 0 && downloadedBytes == totalBytesCount) {
try {
onFinishLoadingFile();
} catch (Exception e) {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
} else {
startDownloadRequest();
}
}
});
} else {
try {
onFinishLoadingFile();
} catch (Exception e) {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
}
}
public void cancel() {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (state == stateFinished || state == stateFailed) {
return;
}
state = stateFailed;
cleanup();
if (requestInfos != null) {
for (int a = 0; a < requestInfos.size(); a++) {
RequestInfo requestInfo = requestInfos.get(a);
if (requestInfo.requestToken != 0) {
ConnectionsManager.getInstance().cancelRequest(requestInfo.requestToken, true);
}
}
}
delegate.didFailedLoadingFile(FileLoadOperation.this, 1);
}
});
}
private void cleanup() {
try {
if (fileOutputStream != null) {
try {
fileOutputStream.getChannel().close();
} catch (Exception e) {
FileLog.e("messenger", e);
}
fileOutputStream.close();
fileOutputStream = null;
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
try {
if (fiv != null) {
fiv.close();
fiv = null;
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
if (delayedRequestInfos != null) {
for (int a = 0; a < delayedRequestInfos.size(); a++) {
RequestInfo requestInfo = delayedRequestInfos.get(a);
/*if (requestInfo.response != null) {
requestInfo.response.disableFree = false;
requestInfo.response.freeResources();
}*/
}
delayedRequestInfos.clear();
}
}
private void onFinishLoadingFile() throws Exception {
if (state != stateDownloading) {
return;
}
state = stateFinished;
cleanup();
if (cacheIvTemp != null) {
cacheIvTemp.delete();
cacheIvTemp = null;
}
if (cacheFileTemp != null) {
boolean renameResult = cacheFileTemp.renameTo(cacheFileFinal);
if (!renameResult) {
if (BuildVars.DEBUG_VERSION) {
FileLog.e("messenger", "unable to rename temp = " + cacheFileTemp + " to final = " + cacheFileFinal + " retry = " + renameRetryCount);
}
renameRetryCount++;
if (renameRetryCount < 3) {
state = stateDownloading;
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
onFinishLoadingFile();
} catch (Exception e) {
delegate.didFailedLoadingFile(FileLoadOperation.this, 0);
}
}
}, 200);
return;
}
cacheFileFinal = cacheFileTemp;
}
}
if (BuildVars.DEBUG_VERSION) {
FileLog.e("messenger", "finished downloading file to " + cacheFileFinal);
}
delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal);
}
private void startDownloadRequest() {
if (state != stateDownloading || totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount || requestInfos.size() + delayedRequestInfos.size() >= currentMaxDownloadRequests) {
return;
}
int count = 1;
if (totalBytesCount > 0) {
count = Math.max(0, currentMaxDownloadRequests - requestInfos.size() - delayedRequestInfos.size());
}
for (int a = 0; a < count; a++) {
if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) {
break;
}
boolean isLast = totalBytesCount <= 0 || a == count - 1 || totalBytesCount > 0 && nextDownloadOffset + currentDownloadChunkSize >= totalBytesCount;
//TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
//req.location = location;
//req.offset = nextDownloadOffset;
//req.limit = currentDownloadChunkSize;
nextDownloadOffset += currentDownloadChunkSize;
final RequestInfo requestInfo = new RequestInfo();
requestInfos.add(requestInfo);
requestInfo.offset = nextDownloadOffset;
requestInfo.requestToken = 0;/*ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
requestInfo.response = (TLRPC.TL_upload_file) response;
processRequestResult(requestInfo, error);
}
}, null, (isForceRequest ? ConnectionsManager.RequestFlagForceDownload : 0) | ConnectionsManager.RequestFlagFailOnServerErrors, datacenter_id, requestsCount % 2 == 0 ? ConnectionsManager.ConnectionTypeDownload : ConnectionsManager.ConnectionTypeDownload2, isLast);*/
requestsCount++;
}
}
public void setDelegate(FileLoadOperationDelegate delegate) {
this.delegate = delegate;
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -17,20 +32,6 @@ import java.util.concurrent.Semaphore;
public class FileLoader {
public interface FileLoaderDelegate {
void fileUploadProgressChanged(String location, float progress, boolean isEncrypted);
void fileDidUploaded(String location, TLRPC.InputFile inputFile, TLRPC.InputEncryptedFile inputEncryptedFile, byte[] key, byte[] iv, long totalFileSize);
void fileDidFailedUpload(String location, boolean isEncrypted);
void fileDidLoaded(String location, File finalFile, int type);
void fileDidFailedLoad(String location, int state);
void fileLoadProgressChanged(String location, float progress);
}
public static final int MEDIA_DIR_IMAGE = 0;
public static final int MEDIA_DIR_AUDIO = 1;
public static final int MEDIA_DIR_VIDEO = 2;
@@ -38,25 +39,6 @@ public class FileLoader {
public static final int MEDIA_DIR_CACHE = 4;
private HashMap<Integer, File> mediaDirs = null;
private volatile DispatchQueue fileLoaderQueue = new DispatchQueue("fileUploadQueue");
private LinkedList<FileUploadOperation> uploadOperationQueue = new LinkedList<>();
private LinkedList<FileUploadOperation> uploadSmallOperationQueue = new LinkedList<>();
private LinkedList<FileLoadOperation> loadOperationQueue = new LinkedList<>();
private LinkedList<FileLoadOperation> audioLoadOperationQueue = new LinkedList<>();
private LinkedList<FileLoadOperation> photoLoadOperationQueue = new LinkedList<>();
private ConcurrentHashMap<String, FileUploadOperation> uploadOperationPaths = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, FileUploadOperation> uploadOperationPathsEnc = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, FileLoadOperation> loadOperationPaths = new ConcurrentHashMap<>();
private HashMap<String, Long> uploadSizes = new HashMap<>();
private FileLoaderDelegate delegate = null;
private int currentLoadOperationsCount = 0;
private int currentAudioLoadOperationsCount = 0;
private int currentPhotoLoadOperationsCount = 0;
private int currentUploadOperationsCount = 0;
private int currentUploadSmallOperationsCount = 0;
private static volatile FileLoader Instance = null;
@@ -77,11 +59,7 @@ public class FileLoader {
mediaDirs = dirs;
}
public File checkDirectory(int type) {
return mediaDirs.get(type);
}
public File getDirectory(int type) {
public File getDirectory(int type) { // always returns the cache directory as this is the only one set in mediaDirs[] - we do not use the other directories at the moment
File dir = mediaDirs.get(type);
if (dir == null && type != MEDIA_DIR_CACHE) {
dir = mediaDirs.get(MEDIA_DIR_CACHE);
@@ -96,418 +74,15 @@ public class FileLoader {
return dir;
}
/*
public void checkUploadNewDataAvailable(final String location, final boolean encrypted, final long finalSize) {
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
FileUploadOperation operation;
if (encrypted) {
operation = uploadOperationPathsEnc.get(location);
} else {
operation = uploadOperationPaths.get(location);
}
if (operation != null) {
operation.checkNewDataAvailable(finalSize);
} else if (finalSize != 0) {
uploadSizes.put(location, finalSize);
}
}
});
}
*/
public void uploadFile(final String location, final boolean encrypted, final boolean small) {
uploadFile(location, encrypted, small, 0);
}
public void uploadFile(final String location, final boolean encrypted, final boolean small, final int estimatedSize) {
if (location == null) {
return;
}
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (encrypted) {
if (uploadOperationPathsEnc.containsKey(location)) {
return;
}
} else {
if (uploadOperationPaths.containsKey(location)) {
return;
}
}
int esimated = estimatedSize;
if (esimated != 0) {
Long finalSize = uploadSizes.get(location);
if (finalSize != null) {
esimated = 0;
uploadSizes.remove(location);
}
}
FileUploadOperation operation = new FileUploadOperation(location, encrypted, esimated);
if (encrypted) {
uploadOperationPathsEnc.put(location, operation);
} else {
uploadOperationPaths.put(location, operation);
}
operation.delegate = new FileUploadOperation.FileUploadOperationDelegate() {
@Override
public void didFinishUploadingFile(final FileUploadOperation operation, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile, final byte[] key, final byte[] iv) {
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (encrypted) {
uploadOperationPathsEnc.remove(location);
} else {
uploadOperationPaths.remove(location);
}
if (small) {
currentUploadSmallOperationsCount--;
if (currentUploadSmallOperationsCount < 1) {
FileUploadOperation operation = uploadSmallOperationQueue.poll();
if (operation != null) {
currentUploadSmallOperationsCount++;
operation.start();
}
}
} else {
currentUploadOperationsCount--;
if (currentUploadOperationsCount < 1) {
FileUploadOperation operation = uploadOperationQueue.poll();
if (operation != null) {
currentUploadOperationsCount++;
operation.start();
}
}
}
if (delegate != null) {
delegate.fileDidUploaded(location, inputFile, inputEncryptedFile, key, iv, operation.getTotalFileSize());
}
}
});
}
@Override
public void didFailedUploadingFile(final FileUploadOperation operation) {
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (encrypted) {
uploadOperationPathsEnc.remove(location);
} else {
uploadOperationPaths.remove(location);
}
if (delegate != null) {
delegate.fileDidFailedUpload(location, encrypted);
}
if (small) {
currentUploadSmallOperationsCount--;
if (currentUploadSmallOperationsCount < 1) {
FileUploadOperation operation = uploadSmallOperationQueue.poll();
if (operation != null) {
currentUploadSmallOperationsCount++;
operation.start();
}
}
} else {
currentUploadOperationsCount--;
if (currentUploadOperationsCount < 1) {
FileUploadOperation operation = uploadOperationQueue.poll();
if (operation != null) {
currentUploadOperationsCount++;
operation.start();
}
}
}
}
});
}
@Override
public void didChangedUploadProgress(FileUploadOperation operation, final float progress) {
if (delegate != null) {
delegate.fileUploadProgressChanged(location, progress, encrypted);
}
}
};
if (small) {
if (currentUploadSmallOperationsCount < 1) {
currentUploadSmallOperationsCount++;
operation.start();
} else {
uploadSmallOperationQueue.add(operation);
}
} else {
if (currentUploadOperationsCount < 1) {
currentUploadOperationsCount++;
operation.start();
} else {
uploadOperationQueue.add(operation);
}
}
}
});
}
public void cancelLoadFile(TLRPC.Document document) {
cancelLoadFile(document, null, null);
}
public void cancelLoadFile(TLRPC.PhotoSize photo) {
cancelLoadFile(null, photo.location, null);
}
public void cancelLoadFile(TLRPC.FileLocation location, String ext) {
cancelLoadFile(null, location, ext);
}
private void cancelLoadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt) {
if (location == null && document == null) {
return;
}
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
String fileName = null;
if (location != null) {
fileName = getAttachFileName(location, locationExt);
} else if (document != null) {
fileName = getAttachFileName(document);
}
if (fileName == null) {
return;
}
FileLoadOperation operation = loadOperationPaths.remove(fileName);
if (operation != null) {
if (MessageObject.isVoiceDocument(document)) {
audioLoadOperationQueue.remove(operation);
} else if (location != null) {
photoLoadOperationQueue.remove(operation);
} else {
loadOperationQueue.remove(operation);
}
operation.cancel();
}
}
});
}
public boolean isLoadingFile(final String fileName) {
final Semaphore semaphore = new Semaphore(0);
final Boolean[] result = new Boolean[1];
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
result[0] = loadOperationPaths.containsKey(fileName);
semaphore.release();
}
});
try {
semaphore.acquire();
} catch (Exception e) {
FileLog.e("messenger", e);
}
return result[0];
}
public void loadFile(TLRPC.PhotoSize photo, String ext, boolean cacheOnly) {
loadFile(null, photo.location, ext, photo.size, false, cacheOnly || (photo != null && photo.size == 0 || photo.location.key != null));
}
public void loadFile(TLRPC.Document document, boolean force, boolean cacheOnly) {
loadFile(document, null, null, 0, force, cacheOnly || document != null && document.key != null);
}
public void loadFile(TLRPC.FileLocation location, String ext, int size, boolean cacheOnly) {
loadFile(null, location, ext, size, true, cacheOnly || size == 0 || (location != null && location.key != null));
}
private void loadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt, final int locationSize, final boolean force, final boolean cacheOnly) {
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
String fileName = null;
if (location != null) {
fileName = getAttachFileName(location, locationExt);
} else if (document != null) {
fileName = getAttachFileName(document);
}
if (fileName == null || fileName.contains("" + Integer.MIN_VALUE)) {
return;
}
FileLoadOperation operation;
operation = loadOperationPaths.get(fileName);
if (operation != null) {
if (force) {
LinkedList<FileLoadOperation> downloadQueue;
if (MessageObject.isVoiceDocument(document)) {
downloadQueue = audioLoadOperationQueue;
} else if (location != null) {
downloadQueue = photoLoadOperationQueue;
} else {
downloadQueue = loadOperationQueue;
}
if (downloadQueue != null) {
int index = downloadQueue.indexOf(operation);
if (index != -1) {
downloadQueue.remove(index);
downloadQueue.add(0, operation);
operation.setForceRequest(true);
}
}
}
return;
}
File tempDir = getDirectory(MEDIA_DIR_CACHE);
File storeDir = tempDir;
int type = MEDIA_DIR_CACHE;
if (location != null) {
operation = new FileLoadOperation(location, locationExt, locationSize);
type = MEDIA_DIR_IMAGE;
} else if (document != null) {
operation = new FileLoadOperation(document);
if (MessageObject.isVoiceDocument(document)) {
type = MEDIA_DIR_AUDIO;
} else if (MessageObject.isVideoDocument(document)) {
type = MEDIA_DIR_VIDEO;
} else {
type = MEDIA_DIR_DOCUMENT;
}
}
if (!cacheOnly) {
storeDir = getDirectory(type);
}
operation.setPaths(storeDir, tempDir);
final String finalFileName = fileName;
final int finalType = type;
loadOperationPaths.put(fileName, operation);
operation.setDelegate(new FileLoadOperation.FileLoadOperationDelegate() {
@Override
public void didFinishLoadingFile(FileLoadOperation operation, File finalFile) {
if (delegate != null) {
delegate.fileDidLoaded(finalFileName, finalFile, finalType);
}
checkDownloadQueue(document, location, finalFileName);
}
@Override
public void didFailedLoadingFile(FileLoadOperation operation, int canceled) {
checkDownloadQueue(document, location, finalFileName);
if (delegate != null) {
delegate.fileDidFailedLoad(finalFileName, canceled);
}
}
@Override
public void didChangedLoadProgress(FileLoadOperation operation, float progress) {
if (delegate != null) {
delegate.fileLoadProgressChanged(finalFileName, progress);
}
}
});
int maxCount = force ? 3 : 1;
if (type == MEDIA_DIR_AUDIO) {
if (currentAudioLoadOperationsCount < maxCount) {
currentAudioLoadOperationsCount++;
operation.start();
} else {
if (force) {
audioLoadOperationQueue.add(0, operation);
} else {
audioLoadOperationQueue.add(operation);
}
}
} else if (location != null) {
if (currentPhotoLoadOperationsCount < maxCount) {
currentPhotoLoadOperationsCount++;
operation.start();
} else {
if (force) {
photoLoadOperationQueue.add(0, operation);
} else {
photoLoadOperationQueue.add(operation);
}
}
} else {
if (currentLoadOperationsCount < maxCount) {
currentLoadOperationsCount++;
operation.start();
} else {
if (force) {
loadOperationQueue.add(0, operation);
} else {
loadOperationQueue.add(operation);
}
}
}
}
});
}
private void checkDownloadQueue(final TLRPC.Document document, final TLRPC.FileLocation location, final String arg1) {
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
loadOperationPaths.remove(arg1);
FileLoadOperation operation;
if (MessageObject.isVoiceDocument(document)) {
currentAudioLoadOperationsCount--;
if (!audioLoadOperationQueue.isEmpty()) {
operation = audioLoadOperationQueue.get(0);
int maxCount = operation.isForceRequest() ? 3 : 1;
if (currentAudioLoadOperationsCount < maxCount) {
operation = audioLoadOperationQueue.poll();
if (operation != null) {
currentAudioLoadOperationsCount++;
operation.start();
}
}
}
} else if (location != null) {
currentPhotoLoadOperationsCount--;
if (!photoLoadOperationQueue.isEmpty()) {
operation = photoLoadOperationQueue.get(0);
int maxCount = operation.isForceRequest() ? 3 : 1;
if (currentPhotoLoadOperationsCount < maxCount) {
operation = photoLoadOperationQueue.poll();
if (operation != null) {
currentPhotoLoadOperationsCount++;
operation.start();
}
}
}
} else {
currentLoadOperationsCount--;
if (!loadOperationQueue.isEmpty()) {
operation = loadOperationQueue.get(0);
int maxCount = operation.isForceRequest() ? 3 : 1;
if (currentLoadOperationsCount < maxCount) {
operation = loadOperationQueue.poll();
if (operation != null) {
currentLoadOperationsCount++;
operation.start();
}
}
}
}
}
});
}
public void setDelegate(FileLoaderDelegate delegate) {
this.delegate = delegate;
return false;
}
public static String getMessageFileName(TLRPC.Message message) {
if (message == null) {
return "";
}
if (message instanceof TLRPC.TL_messageService) {
/*if (message instanceof TLRPC.TL_messageService) {
if (message.action.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.action.photo.sizes;
if (sizes.size() > 0) {
@@ -517,7 +92,7 @@ public class FileLoader {
}
}
}
} else {
} else*/ {
if (message.media instanceof TLRPC.TL_messageMediaDocument) {
return getAttachFileName(message.media.document);
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
@@ -528,7 +103,7 @@ public class FileLoader {
return getAttachFileName(sizeFull);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
} /*else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
if (message.media.webpage.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.media.webpage.photo.sizes;
if (sizes.size() > 0) {
@@ -540,7 +115,7 @@ public class FileLoader {
} else if (message.media.webpage.document != null) {
return getAttachFileName(message.media.webpage.document);
}
}
}*/
}
return "";
}
@@ -549,7 +124,7 @@ public class FileLoader {
if (message == null) {
return new File("");
}
if (message instanceof TLRPC.TL_messageService) {
/*if (message instanceof TLRPC.TL_messageService) {
if (message.action.photo != null) {
ArrayList<TLRPC.PhotoSize> sizes = message.action.photo.sizes;
if (sizes.size() > 0) {
@@ -559,7 +134,7 @@ public class FileLoader {
}
}
}
} else {
} else*/ {
if (message.media instanceof TLRPC.TL_messageMediaDocument) {
return getPathToAttach(message.media.document);
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
@@ -570,7 +145,7 @@ public class FileLoader {
return getPathToAttach(sizeFull);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
} /*else if (message.media instanceof TLRPC.TL_messageMediaWebPage) {
if (message.media.webpage.document != null) {
return getPathToAttach(message.media.webpage.document);
} else if (message.media.webpage.photo != null) {
@@ -582,7 +157,7 @@ public class FileLoader {
}
}
}
}
}*/
}
return new File("");
}
@@ -1,15 +1,28 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.util.Log;
import com.b44t.messenger.time.FastDateFormat;
import java.io.File;
@@ -22,7 +35,6 @@ public class FileLog {
private FastDateFormat dateFormat = null;
private DispatchQueue logQueue = null;
private File currentFile = null;
private File networkFile = null;
private static volatile FileLog Instance = null;
public static FileLog getInstance() {
@@ -39,10 +51,7 @@ public class FileLog {
}
public FileLog() {
if (!BuildVars.DEBUG_VERSION) {
return;
}
dateFormat = FastDateFormat.getInstance("dd_MM_yyyy_HH_mm_ss", Locale.US);
dateFormat = FastDateFormat.getInstance("yyyyMMdd_HHmmss", Locale.US);
try {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
if (sdCard == null) {
@@ -66,37 +75,14 @@ public class FileLog {
}
}
public static String getNetworkLogPath() {
if (!BuildVars.DEBUG_VERSION) {
return "";
}
try {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
if (sdCard == null) {
return "";
}
File dir = new File(sdCard.getAbsolutePath() + "/logs");
dir.mkdirs();
getInstance().networkFile = new File(dir, getInstance().dateFormat.format(System.currentTimeMillis()) + "_net.txt");
return getInstance().networkFile.getAbsolutePath();
} catch (Throwable e) {
e.printStackTrace();
}
return "";
}
public static void e(final String tag, final String message, final Throwable exception) {
if (!BuildVars.DEBUG_VERSION) {
return;
}
Log.e(tag, message, exception);
private static void log(final String what, final String tag, final String message)
{
if (getInstance().streamWriter != null) {
getInstance().logQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + " " + message + "\n");
getInstance().streamWriter.write(exception.toString());
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " " + what + "/" + tag + ": " + message + "\n");
getInstance().streamWriter.flush();
} catch (Exception e) {
e.printStackTrace();
@@ -107,109 +93,14 @@ public class FileLog {
}
public static void e(final String tag, final String message) {
if (!BuildVars.DEBUG_VERSION) {
return;
}
Log.e(tag, message);
if (getInstance().streamWriter != null) {
getInstance().logQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "" + message + "\n");
getInstance().streamWriter.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
public static void e(final String tag, final Throwable e) {
if (!BuildVars.DEBUG_VERSION) {
return;
}
e.printStackTrace();
if (getInstance().streamWriter != null) {
getInstance().logQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "" + e + "\n");
StackTraceElement[] stack = e.getStackTrace();
for (int a = 0; a < stack.length; a++) {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "" + stack[a] + "\n");
}
getInstance().streamWriter.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
e.printStackTrace();
}
}
public static void d(final String tag, final String message) {
if (!BuildVars.DEBUG_VERSION) {
return;
}
Log.d(tag, message);
if (getInstance().streamWriter != null) {
getInstance().logQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " D/" + tag + "" + message + "\n");
getInstance().streamWriter.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
log("E", tag, message);
}
public static void w(final String tag, final String message) {
if (!BuildVars.DEBUG_VERSION) {
return;
}
Log.w(tag, message);
if (getInstance().streamWriter != null) {
getInstance().logQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " W/" + tag + ": " + message + "\n");
getInstance().streamWriter.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
log("W", tag, message);
}
public static void cleanupLogs() {
File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null);
if (sdCard == null) {
return;
}
File dir = new File (sdCard.getAbsolutePath() + "/logs");
File[] files = dir.listFiles();
if (files != null) {
for (int a = 0; a < files.length; a++) {
File file = files[a];
if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) {
continue;
}
if (getInstance().networkFile != null && file.getAbsolutePath().equals(getInstance().networkFile.getAbsolutePath())) {
continue;
}
file.delete();
}
}
public static void i(final String tag, final String message) {
log("I", tag, message);
}
}
@@ -1,79 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import java.io.FileInputStream;
public class FileUploadOperation {
public int state = 0;
public FileUploadOperationDelegate delegate;
private int requestToken = 0;
private long totalFileSize = 0;
private boolean isEncrypted = false;
private int estimatedSize = 0;
private FileInputStream stream;
public interface FileUploadOperationDelegate {
void didFinishUploadingFile(FileUploadOperation operation, TLRPC.InputFile inputFile, TLRPC.InputEncryptedFile inputEncryptedFile, byte[] key, byte[] iv);
void didFailedUploadingFile(FileUploadOperation operation);
void didChangedUploadProgress(FileUploadOperation operation, float progress);
}
public FileUploadOperation(String location, boolean encrypted, int estimated) {
isEncrypted = encrypted;
estimatedSize = estimated;
}
public long getTotalFileSize() {
return totalFileSize;
}
public void start() {
}
public void cancel() {
if (state == 3) {
return;
}
state = 2;
if (requestToken != 0) {
ConnectionsManager.getInstance().cancelRequest(requestToken, true);
}
delegate.didFailedUploadingFile(this);
cleanup();
}
private void cleanup() {
}
/*
protected void checkNewDataAvailable(final long finalSize) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (estimatedSize != 0 && finalSize != 0) {
estimatedSize = 0;
totalFileSize = finalSize;
totalPartsCount = (int) (totalFileSize + uploadChunkSize - 1) / uploadChunkSize;
if (started) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("uploadinfo", Activity.MODE_PRIVATE);
storeFileUploadInfo(preferences);
}
}
if (requestToken == 0) {
startUploadRequest();
}
}
});
}
*/
}
File diff suppressed because it is too large Load Diff
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -14,6 +29,7 @@ import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
@@ -27,6 +43,7 @@ import com.b44t.ui.Components.AnimatedFileDrawable;
public class ImageReceiver implements NotificationCenter.NotificationCenterDelegate {
public interface ImageReceiverDelegate {
void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb);
}
@@ -43,6 +60,11 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
public String ext;
}
public String m_userDataUnique = ""; // used to discard images loaded and no longer required as there was a new request
// before, we used "private static HashMap<View, String> s_viewBindings = new HashMap<>();" in ContactsController -
// however, this was a bad idea as this resulted in _lots_ of objects that were never freed...
private View parentView;
private Integer tag;
private Integer thumbTag;
@@ -349,12 +371,10 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
setImageBackup.ext = currentExt;
setImageBackup.cacheOnly = currentCacheOnly;
}
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReplacedPhotoInMemCache);
clearImage();
}
public boolean onAttachedToWindow() {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReplacedPhotoInMemCache);
if (setImageBackup != null && (setImageBackup.fileLocation != null || setImageBackup.httpUrl != null || setImageBackup.thumbLocation != null || setImageBackup.thumb != null)) {
setImage(setImageBackup.fileLocation, setImageBackup.httpUrl, setImageBackup.filter, setImageBackup.thumb, setImageBackup.thumbLocation, setImageBackup.thumbFilter, setImageBackup.size, setImageBackup.ext, setImageBackup.cacheOnly);
return true;
@@ -463,7 +483,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
FileLog.e("messenger", e);
}
canvas.restore();
} else {
@@ -508,7 +528,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
FileLog.e("messenger", e);
}
}
@@ -545,7 +565,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly);
FileLog.e("messenger", e);
}
}
canvas.restore();
@@ -560,7 +580,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
drawable.setAlpha(alpha);
drawable.draw(canvas);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
}
@@ -642,7 +662,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
checkAlphaAnimation(animationNotReady);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return false;
}
@@ -1036,26 +1056,6 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
}
}
}
} else if (id == NotificationCenter.didReplacedPhotoInMemCache) {
String oldKey = (String) args[0];
if (currentKey != null && currentKey.equals(oldKey)) {
currentKey = (String) args[1];
currentImageLocation = (TLRPC.FileLocation) args[2];
}
if (currentThumbKey != null && currentThumbKey.equals(oldKey)) {
currentThumbKey = (String) args[1];
currentThumbLocation = (TLRPC.FileLocation) args[2];
}
if (setImageBackup != null) {
if (currentKey != null && currentKey.equals(oldKey)) {
currentKey = (String) args[1];
currentImageLocation = (TLRPC.FileLocation) args[2];
}
if (currentThumbKey != null && currentThumbKey.equals(oldKey)) {
currentThumbKey = (String) args[1];
currentThumbLocation = (TLRPC.FileLocation) args[2];
}
}
}
}
}
@@ -0,0 +1,114 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.util.Locale;
public class KeepAliveService extends Service {
static KeepAliveService s_this = null;
@Override
public void onCreate() {
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onCreate()");
// there's nothing more to do here as all initialisation stuff is already done in
// ApplicationLoader.onCreate() which is called before this broadcast is sended.
s_this = this;
setSelfAsForeground();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// START_STICKY ensured, the service is recreated as soon it is terminted for any reasons.
// as ApplicationLoader.onCreate() is called before a service starts, there is no more to do here,
// the app is just running fine.
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onStartCommand()");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
MrMailbox.log_i("DeltaChat", "*** KeepAliveService.onDestroy()");
// the service will be restarted due to START_STICKY automatically, there's nothing more to do.
}
private void setSelfAsForeground() {
stopForeground(true);
startForeground(FG_NOTIFICATION_ID, createNotification()); // TODO: if we target Android O, we should use startServiceInForeground()
}
static public KeepAliveService getInstance()
{
return s_this; // may be null
}
/* The notification
* A notification is required for a foreground service; and without a foreground service,
* Delta Chat won't get new messages reliable
**********************************************************************************************/
public static final int FG_NOTIFICATION_ID = 4142;
private Notification createNotification()
{
// a notification _must_ contain a small icon, a title and a text, see https://developer.android.com/guide/topics/ui/notifiers/notifications.html#Required
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
if( MrMailbox.isConfigured()!=0) {
builder.setContentTitle(LocaleController.formatString("", R.string.PermNotificationTitle, MrMailbox.getConfig("addr", "")));
builder.setContentText(getString(R.string.PermNotificationText));
}
else {
builder.setContentTitle(getString(R.string.AppName));
builder.setContentText(getString(R.string.AccountNotConfigured));
}
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN ) {
builder.setPriority(NotificationCompat.PRIORITY_MIN);
}
builder.setWhen(0);
builder.setSmallIcon(R.drawable.notification_permanent);
return builder.build();
}
public void updateForegroundNotification()
{
// update the notification by simply creating a new notification with the same ID, see https://developer.android.com/training/notify-user/managing.html#Updating
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(FG_NOTIFICATION_ID, createNotification());
}
}
File diff suppressed because it is too large Load Diff
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,675 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.app.Activity;
import android.content.SharedPreferences;
import com.b44t.messenger.query.DraftQuery;
import com.b44t.messenger.query.MessagesQuery;
import com.b44t.messenger.query.SearchQuery;
import com.b44t.ui.ActionBar.BaseFragment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class MessagesController implements NotificationCenter.NotificationCenterDelegate {
public ArrayList<TLRPC.TL_dialog> dialogs = new ArrayList<>();
public ArrayList<TLRPC.TL_dialog> dialogsServerOnly = new ArrayList<>();
public ArrayList<TLRPC.TL_dialog> dialogsGroupsOnly = new ArrayList<>();
public int nextDialogsCacheOffset;
public ConcurrentHashMap<Long, TLRPC.TL_dialog> dialogs_dict = new ConcurrentHashMap<>(100, 1.0f, 2);
public HashMap<Long, MessageObject> dialogMessage = new HashMap<>();
public HashMap<Long, MessageObject> dialogMessagesByRandomIds = new HashMap<>();
public HashMap<Integer, MessageObject> dialogMessagesByIds = new HashMap<>();
public HashMap<Long, CharSequence> printingStrings = new HashMap<>();
public ConcurrentHashMap<Integer, Integer> onlinePrivacy = new ConcurrentHashMap<>(20, 1.0f, 2);
private HashMap<String, ArrayList<MessageObject>> reloadingWebpages = new HashMap<>();
public boolean loadingDialogs = false;
public boolean dialogsEndReached = false;
public int secretWebpagePreview = 2;
private String uploadingAvatar = null;
public boolean enableJoined = true;
public int fontSize = AndroidUtilities.dp(16);
public int ratingDecay;
public static final int UPDATE_MASK_NAME = 1;
public static final int UPDATE_MASK_AVATAR = 2;
public static final int UPDATE_MASK_STATUS = 4;
public static final int UPDATE_MASK_CHAT_AVATAR = 8;
public static final int UPDATE_MASK_CHAT_NAME = 16;
public static final int UPDATE_MASK_CHAT_MEMBERS = 32;
public static final int UPDATE_MASK_USER_PRINT = 64;
public static final int UPDATE_MASK_READ_DIALOG_MESSAGE = 256;
public static final int UPDATE_MASK_SELECT_DIALOG = 512;
public static final int UPDATE_MASK_NEW_MESSAGE = 2048;
public static final int UPDATE_MASK_SEND_STATE = 4096;
public static final int UPDATE_MASK_CHANNEL = 8192;
public static final int UPDATE_MASK_CHAT_ADMINS = 16384;
private static volatile MessagesController Instance = null;
private final Comparator<TLRPC.TL_dialog> dialogComparator = new Comparator<TLRPC.TL_dialog>() {
@Override
public int compare(TLRPC.TL_dialog dialog1, TLRPC.TL_dialog dialog2) {
TLRPC.DraftMessage draftMessage = DraftQuery.getDraft(dialog1.id);
int date1 = draftMessage != null && draftMessage.date >= dialog1.last_message_date ? draftMessage.date : dialog1.last_message_date;
draftMessage = DraftQuery.getDraft(dialog2.id);
int date2 = draftMessage != null && draftMessage.date >= dialog2.last_message_date ? draftMessage.date : dialog2.last_message_date;
if (date1 < date2) {
return 1;
} else if (date1 > date2) {
return -1;
}
return 0;
}
};
public static MessagesController getInstance() {
MessagesController localInstance = Instance;
if (localInstance == null) {
synchronized (MessagesController.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new MessagesController();
}
}
}
return localInstance;
}
public MessagesController() {
ImageLoader.getInstance();
//MessagesStorage.getInstance();
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidUpload);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailUpload);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageReceivedByServer);
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
enableJoined = preferences.getBoolean("EnableContactJoined", true);
preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
secretWebpagePreview = preferences.getInt("secretWebpage2", 2);
ratingDecay = preferences.getInt("ratingDecay", 2419200);
fontSize = preferences.getInt("fons_size", AndroidUtilities.isTablet() ? 18 : 16);
}
public static TLRPC.InputUser getInputUser(TLRPC.User user) {
if (user == null) {
return new TLRPC.TL_inputUserEmpty();
}
TLRPC.InputUser inputUser;
if (user.id == UserConfig.getClientUserId()) {
inputUser = new TLRPC.TL_inputUserSelf();
} else {
inputUser = new TLRPC.TL_inputUser();
inputUser.user_id = user.id;
inputUser.access_hash = user.access_hash;
}
return inputUser;
}
public static TLRPC.InputUser getInputUser(int user_id) {
TLRPC.User user = getInstance().getUser(user_id);
return getInputUser(user);
}
public static TLRPC.InputPeer getInputPeer(int id) {
TLRPC.InputPeer inputPeer;
/*if (id < 0) {
TLRPC.Chat chat = getInstance().getChat(-id);
if (ChatObject.isChannel(chat)) {
inputPeer = new TLRPC.TL_inputPeerChannel();
inputPeer.channel_id = -id;
inputPeer.access_hash = chat.access_hash;
} else {
inputPeer = new TLRPC.TL_inputPeerChat();
inputPeer.chat_id = -id;
}
} else */ {
TLRPC.User user = getInstance().getUser(id);
inputPeer = new TLRPC.TL_inputPeerUser();
inputPeer.user_id = id;
if (user != null) {
inputPeer.access_hash = user.access_hash;
}
}
return inputPeer;
}
public static TLRPC.Peer getPeer(int id) {
TLRPC.Peer inputPeer;
if (id < 0) {
inputPeer = new TLRPC.TL_peerChat();
inputPeer.chat_id = -id;
} else {
inputPeer = new TLRPC.TL_peerUser();
inputPeer.user_id = id;
}
return inputPeer;
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.FileDidUpload) {
final String location = (String) args[0];
final TLRPC.InputFile file = (TLRPC.InputFile) args[1];
if (uploadingAvatar != null && uploadingAvatar.equals(location)) {
/*TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto();
req.caption = "";
req.crop = new TLRPC.TL_inputPhotoCropAuto();
req.file = file;
req.geo_point = new TLRPC.TL_inputGeoPointEmpty();*/
/*ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
TLRPC.User user = getUser(UserConfig.getClientUserId());
if (user == null) {
user = UserConfig.getCurrentUser();
putUser(user, true);
} else {
UserConfig.setCurrentUser(user);
}
if (user == null) {
return;
}
TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response;
ArrayList<TLRPC.PhotoSize> sizes = photo.photo.sizes;
TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100);
TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000);
user.photo = new TLRPC.TL_userProfilePhoto();
user.photo.photo_id = photo.photo.id;
if (smallSize != null) {
user.photo.photo_small = smallSize.location;
}
if (bigSize != null) {
user.photo.photo_big = bigSize.location;
} else if (smallSize != null) {
user.photo.photo_small = smallSize.location;
}
//MessagesStorage.getInstance().clearUserPhotos(user.id);
ArrayList<TLRPC.User> users = new ArrayList<>();
users.add(user);
//MessagesStorage.getInstance().putUsersAndChats(users, null, false, true);
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR);
UserConfig.saveConfig(true);
}
});
}
}
});*/
}
} else if (id == NotificationCenter.FileDidFailUpload) {
final String location = (String) args[0];
if (uploadingAvatar != null && uploadingAvatar.equals(location)) {
uploadingAvatar = null;
}
} else if (id == NotificationCenter.messageReceivedByServer) {
Integer msgId = (Integer) args[0];
Integer newMsgId = (Integer) args[1];
Long did = (Long) args[3];
MessageObject obj = dialogMessage.get(did);
if (obj != null && obj.getId() == msgId) {
obj.messageOwner.id = newMsgId;
obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
TLRPC.TL_dialog dialog = dialogs_dict.get(did);
if (dialog != null) {
if (dialog.top_message == msgId) {
dialog.top_message = newMsgId;
}
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
obj = dialogMessagesByIds.remove(msgId);
if (obj != null) {
dialogMessagesByIds.put(newMsgId, obj);
}
}
}
/*
public void cleanup() {
ContactsController.getInstance().cleanup();
MediaController.getInstance().cleanup();
NotificationsController.getInstance().cleanup();
SendMessagesHelper.getInstance().cleanup();
//SecretChatHelper.getInstance().cleanup();
StickersQuery.cleanup();
SearchQuery.cleanup();
DraftQuery.cleanup();
reloadingWebpages.clear();
reloadingWebpagesPending.clear();
dialogs_dict.clear();
dialogs_read_inbox_max.clear();
dialogs_read_outbox_max.clear();
dialogs.clear();
channelViewsToSend.clear();
channelViewsToReload.clear();
dialogsServerOnly.clear();
dialogsGroupsOnly.clear();
dialogMessagesByIds.clear();
dialogMessagesByRandomIds.clear();
users.clear();
usersByUsernames.clear();
chats.clear();
dialogMessage.clear();
printingUsers.clear();
printingStrings.clear();
printingStringsTypes.clear();
onlinePrivacy.clear();
loadingPeerSettings.clear();
lastPrintingStringCount = 0;
nextDialogsCacheOffset = 0;
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
gettingUnknownChannels.clear();
createdDialogIds.clear();
gettingDifference = false;
}
});
blockedUsers.clear();
sendingTypings.clear();
loadingFullUsers.clear();
loadedFullUsers.clear();
reloadingMessages.clear();
loadingFullChats.clear();
loadingFullParticipants.clear();
loadedFullParticipants.clear();
loadedFullChats.clear();
currentDeletingTaskTime = 0;
currentDeletingTaskMids = null;
gettingNewDeleteTask = false;
loadingDialogs = false;
dialogsEndReached = false;
loadingBlockedUsers = false;
firstGettingTask = false;
updatingState = false;
offlineSent = false;
registeringForPush = false;
uploadingAvatar = null;
statusRequest = 0;
statusSettingState = 0;
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
//ConnectionsManager.getInstance().setIsUpdating(false);
updatesQueueChannels.clear();
updatesStartWaitTimeChannels.clear();
gettingDifferenceChannels.clear();
channelsPts.clear();
shortPollChannels.clear();
needShortPollChannels.clear();
}
});
if (currentDeleteTaskRunnable != null) {
Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable);
currentDeleteTaskRunnable = null;
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
*/
public TLRPC.User getUser(Integer id) {
// EDIT BY MR - additional information should be loaded as needed by the caller
TLRPC.User u = new TLRPC.User();
u.id = id;
return u;
}
public TLRPC.Chat getChat(Integer id) {
return null;
}
public void deleteMessages(ArrayList<Integer> messages, ArrayList<Long> randoms, Object encryptedChat, final int channelId) {
}
public MediaController.SearchImage saveGif(TLRPC.Document document) {
MediaController.SearchImage searchImage = new MediaController.SearchImage();
searchImage.type = 2;
searchImage.document = document;
searchImage.date = (int) (System.currentTimeMillis() / 1000);
searchImage.id = "" + searchImage.document.id;
ArrayList<MediaController.SearchImage> arrayList = new ArrayList<>();
arrayList.add(searchImage);
//MessagesStorage.getInstance().putWebRecent(arrayList);
/*TLRPC.TL_messages_saveGif req = new TLRPC.TL_messages_saveGif();
req.id = new TLRPC.TL_inputDocument();
req.id.id = searchImage.document.id;
req.id.access_hash = searchImage.document.access_hash;
req.unsave = false;
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
}
});*/
return searchImage;
}
public void cancelTyping(int action, long dialog_id) {
}
public void sendTyping(final long dialog_id, final int action, int classGuid) {
}
public void reloadWebPages(final long dialog_id, HashMap<String, ArrayList<MessageObject>> webpagesToReload) {
for (HashMap.Entry<String, ArrayList<MessageObject>> entry : webpagesToReload.entrySet()) {
final String url = entry.getKey();
final ArrayList<MessageObject> messages = entry.getValue();
ArrayList<MessageObject> arrayList = reloadingWebpages.get(url);
if (arrayList == null) {
arrayList = new ArrayList<>();
reloadingWebpages.put(url, arrayList);
}
arrayList.addAll(messages);
/*TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview();
req.message = url;
ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(final TLObject response, final TLRPC.TL_error error) {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
ArrayList<MessageObject> arrayList = reloadingWebpages.remove(url);
if (arrayList == null) {
return;
}
TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages();
if (!(response instanceof TLRPC.TL_messageMediaWebPage)) {
for (int a = 0; a < arrayList.size(); a++) {
arrayList.get(a).messageOwner.media.webpage = new TLRPC.TL_webPageEmpty();
messagesRes.messages.add(arrayList.get(a).messageOwner);
}
} else {
TLRPC.TL_messageMediaWebPage media = (TLRPC.TL_messageMediaWebPage) response;
if (media.webpage instanceof TLRPC.TL_webPage || media.webpage instanceof TLRPC.TL_webPageEmpty) {
for (int a = 0; a < arrayList.size(); a++) {
arrayList.get(a).messageOwner.media.webpage = media.webpage;
if (a == 0) {
ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner);
}
messagesRes.messages.add(arrayList.get(a).messageOwner);
}
} else {
reloadingWebpagesPending.put(media.webpage.id, arrayList);
}
}
if (!messagesRes.messages.isEmpty()) {
//MessagesStorage.getInstance().putMessages(messagesRes, dialog_id, -2, 0, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList);
}
}
});
}
});*/
}
}
public void loadDialogs(final int offset, final int count, boolean fromCache) {
if (loadingDialogs) {
return;
}
loadingDialogs = true;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
FileLog.e("messenger", "load cacheOffset = " + offset + " count = " + count + " cache = " + fromCache);
if (fromCache) {
//MessagesStorage.getInstance().getDialogs(offset == 0 ? 0 : nextDialogsCacheOffset, count);
} else {
/*
TLRPC.TL_messages_getDialogs req = new TLRPC.TL_messages_getDialogs();
req.limit = count;
boolean found = false;
for (int a = dialogs.size() - 1; a >= 0; a--) {
TLRPC.TL_dialog dialog = dialogs.get(a);
int lower_id = (int) dialog.id;
int high_id = (int) (dialog.id >> 32);
if (lower_id != 0 && high_id != 1 && dialog.top_message > 0) {
MessageObject message = dialogMessage.get(dialog.id);
if (message != null && message.getId() > 0) {
req.offset_date = message.messageOwner.date;
req.offset_id = message.messageOwner.id;
int id;
if (message.messageOwner.to_id.channel_id != 0) {
id = -message.messageOwner.to_id.channel_id;
} else if (message.messageOwner.to_id.chat_id != 0) {
id = -message.messageOwner.to_id.chat_id;
} else {
id = message.messageOwner.to_id.user_id;
}
req.offset_peer = getInputPeer(id);
found = true;
break;
}
}
}
if (!found) {
req.offset_peer = new TLRPC.TL_inputPeerEmpty();
}
*/
/*ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
//final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response;
//processLoadedDialogs(dialogsRes, null, 0, count, 0, false, false);
}
}
});*/
}
}
public void markMessageContentAsRead(final MessageObject messageObject) {
}
public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) {
}
public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int max_date, final boolean was, final boolean popup) {
}
public void addUserToChat(final int chat_id, final TLRPC.User user, final TLRPC.ChatFull info, int count_fwd, String botHash, final BaseFragment fragment) {
}
public void changeChatAvatar(int chat_id, TLRPC.InputFile uploadedAvatar) {
/*TLObject request;
{
TLRPC.TL_messages_editChatPhoto req = new TLRPC.TL_messages_editChatPhoto();
req.chat_id = chat_id;
if (uploadedAvatar != null) {
req.photo = new TLRPC.TL_inputChatUploadedPhoto();
req.photo.file = uploadedAvatar;
req.photo.crop = new TLRPC.TL_inputPhotoCropAuto();
} else {
req.photo = new TLRPC.TL_inputChatPhotoEmpty();
}
request = req;
}*/
/*ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error != null) {
return;
}
processUpdates((TLRPC.Updates) response, false);
}
}, ConnectionsManager.RequestFlagInvokeAfter);*/
}
public boolean isDialogMuted(long dialog_id) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
int mute_type = preferences.getInt("notify2_" + dialog_id, 0);
if (mute_type == 2) {
return true;
} else if (mute_type == 3) {
int mute_until = preferences.getInt("notifyuntil_" + dialog_id, 0);
if (mute_until >= ConnectionsManager.getInstance().getCurrentTime()) {
return true;
}
}
return false;
}
protected void updateInterfaceWithMessages(long uid, ArrayList<MessageObject> messages) {
updateInterfaceWithMessages(uid, messages, false);
}
protected static void addNewGifToRecent(TLRPC.Document document, int date) {
ArrayList<MediaController.SearchImage> arrayList = new ArrayList<>();
MediaController.SearchImage searchImage = new MediaController.SearchImage();
searchImage.type = 2;
searchImage.document = document;
searchImage.date = date;
searchImage.id = "" + searchImage.document.id;
arrayList.add(searchImage);
//MessagesStorage.getInstance().putWebRecent(arrayList);
}
protected void updateInterfaceWithMessages(final long uid, final ArrayList<MessageObject> messages, boolean isBroadcast) {
if (messages == null || messages.isEmpty()) {
return;
}
boolean isEncryptedChat = ((int) uid) == 0;
MessageObject lastMessage = null;
int channelId = 0;
boolean updateRating = false;
for (int a = 0; a < messages.size(); a++) {
MessageObject message = messages.get(a);
if (lastMessage == null || (!isEncryptedChat && message.getId() > lastMessage.getId() || (isEncryptedChat || message.getId() < 0 && lastMessage.getId() < 0) && message.getId() < lastMessage.getId()) || message.messageOwner.date > lastMessage.messageOwner.date) {
lastMessage = message;
if (message.messageOwner.to_id.channel_id != 0) {
channelId = message.messageOwner.to_id.channel_id;
}
}
if (message.isOut() && message.isNewGif() && !message.isSending() && !message.isForwarded()) {
addNewGifToRecent(message.messageOwner.media.document, message.messageOwner.date);
}
if (message.isOut() && message.isSent()) {
updateRating = true;
}
}
MessagesQuery.loadReplyMessagesForMessages(messages, uid);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceivedNewMessages, uid, messages);
if (lastMessage == null) {
return;
}
TLRPC.TL_dialog dialog = dialogs_dict.get(uid);
boolean changed = false;
if (dialog == null) {
if (!isBroadcast) {
TLRPC.Chat chat = getChat(channelId);
if (channelId != 0 && chat == null || chat != null && chat.left) {
return;
}
dialog = new TLRPC.TL_dialog();
dialog.id = uid;
dialog.unread_count = 0;
dialog.top_message = lastMessage.getId();
dialog.last_message_date = lastMessage.messageOwner.date;
//dialog.flags = ChatObject.isChannel(chat) ? 1 : 0;
dialogs_dict.put(uid, dialog);
dialogs.add(dialog);
dialogMessage.put(uid, lastMessage);
if (lastMessage.messageOwner.to_id.channel_id == 0) {
dialogMessagesByIds.put(lastMessage.getId(), lastMessage);
if (lastMessage.messageOwner.random_id != 0) {
dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage);
}
}
nextDialogsCacheOffset++;
changed = true;
}
} else {
if ((dialog.top_message > 0 && lastMessage.getId() > 0 && lastMessage.getId() > dialog.top_message) ||
(dialog.top_message < 0 && lastMessage.getId() < 0 && lastMessage.getId() < dialog.top_message) ||
!dialogMessage.containsKey(uid) || dialog.top_message < 0 || dialog.last_message_date <= lastMessage.messageOwner.date) {
MessageObject object = dialogMessagesByIds.remove(dialog.top_message);
if (object != null && object.messageOwner.random_id != 0) {
dialogMessagesByRandomIds.remove(object.messageOwner.random_id);
}
dialog.top_message = lastMessage.getId();
if (!isBroadcast) {
dialog.last_message_date = lastMessage.messageOwner.date;
changed = true;
}
dialogMessage.put(uid, lastMessage);
if (lastMessage.messageOwner.to_id.channel_id == 0) {
dialogMessagesByIds.put(lastMessage.getId(), lastMessage);
if (lastMessage.messageOwner.random_id != 0) {
dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage);
}
}
}
}
if (changed) {
sortDialogs(null);
}
if (updateRating) {
SearchQuery.increasePeerRaiting(uid);
}
}
public void sortDialogs(HashMap<Integer, TLRPC.Chat> chatsDict) {
dialogsServerOnly.clear();
dialogsGroupsOnly.clear();
Collections.sort(dialogs, dialogComparator);
for (int a = 0; a < dialogs.size(); a++) {
TLRPC.TL_dialog d = dialogs.get(a);
int high_id = (int) (d.id >> 32);
int lower_id = (int) d.id;
if (lower_id != 0 && high_id != 1) {
dialogsServerOnly.add(d);
/*if (DialogObject.isChannel(d)) {
TLRPC.Chat chat = getChat(-lower_id);
if (chat != null && (chat.megagroup && chat.editor || chat.creator)) {
dialogsGroupsOnly.add(d);
}
} else*/ if (lower_id < 0) {
/*if (chatsDict != null) {
TLRPC.Chat chat = chatsDict.get(-lower_id);
if (chat != null && chat.migrated_to != null) {
dialogs.remove(a);
a--;
continue;
}
}*/
dialogsGroupsOnly.add(d);
}
}
}
}
}
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,13 +20,14 @@
*******************************************************************************
*
* File: MrChat.java
* Authors: Björn Petersen
* Purpose: Wrap around mrchat_t
*
******************************************************************************/
package com.b44t.messenger;
import android.text.TextUtils;
public class MrChat {
public final static int MR_CHAT_UNDEFINED = 0;
@@ -44,20 +45,13 @@ public class MrChat {
MrChatUnref(m_hChat);
}
public int getId() {
return MrChatGetId(m_hChat);
}
public int getType() {
return MrChatGetType(m_hChat);
}
public native int getId();
public native int getType();
public native String getName();
public native String getSubtitle();
public String getName() {
return MrChatGetName(m_hChat);
}
public String getSubtitle() {
return MrChatGetSubtitle(m_hChat);
}
public static int MR_CHAT_PARAM_UNPROMOTED = 'U';
public native int getParamInt(int key, int def);
public String getDraft() {
return MrChatGetDraft(m_hChat);
@@ -82,29 +76,18 @@ public class MrChat {
return MrChatGetTotalMsgCount(m_hChat);
}
public int sendText(String text) {
return MrChatSendText(m_hChat, text);
}
public native int sendText(String text);
public int sendMedia(int type, String file, String mime, int w, int h, int time_ms) {
return MrChatSendMedia(m_hChat, type, file, mime, w, h, time_ms);
}
public native int sendMedia(int type, String file, String mime, int w, int h, int time_ms, String author, String trackname);
private long m_hChat;
private long m_hChat; // must not be renamed as referenced by JNI under the name "m_hChat"
private native static void MrChatUnref (long hChat);
private native static int MrChatGetId (long hChat);
private native static int MrChatGetType (long hChat);
private native static String MrChatGetName (long hChat);
private native static String MrChatGetSubtitle (long hChat);
private native static String MrChatGetDraft (long hChat); // returns null for "no draft"
private native static long MrChatGetDraftTimestamp (long hChat); // returns 0 for "no draft"
private native static int MrChatGetDraftReplyToMsgId (long hChat); // returns 0 for "no draft"
private native static int MrChatSetDraft (long hChat, String draft/*NULL=delete*/, long replyToMsgId);
private native static int MrChatGetUnseenCount (long hChat);
private native static int MrChatGetTotalMsgCount (long hChat);
private native static long MrChatGetSummary (long hChat); // returns hPoortext
private native static int MrChatSendText (long hChat, String text); // returns message id
private native static int MrChatSendMedia (long hChat, int type, String file, String mime, int w, int h, int time_ms);
/* additional functions that are not 1:1 available in the backend
@@ -128,7 +111,51 @@ public class MrChat {
return ret;
}
public long GetCPtr() {
public long getCPtr() {
return m_hChat;
}
public TLRPC.DraftMessage getDraftMessageObj() {
if( getId() == 0 ) {
return null;
}
TLRPC.DraftMessage ret = new TLRPC.DraftMessage();
ret.message = getDraft();
if( ret.message==null || ret.message.isEmpty() ) {
return null;
}
ret.date = (int)getDraftTimestamp();
ret.reply_to_msg_id = getDraftReplyToMsgId();
return ret;
}
public void saveDraft(CharSequence message, TLRPC.Message replyToMessage) {
if( message == null || TextUtils.isEmpty(message) ) {
setDraft(null, 0);
}
else {
setDraft(message.toString(), 0);
}
}
public void cleanDraft()
{
setDraft(null, 0);
}
public String getNameNAddr()
{
// returns name of group chats or name+e-mail-address for normal chats
String name = "ErrGrpNameNAddr";
if( getType()==MR_CHAT_GROUP ) {
name = getName();
}
else {
int contacts[] = MrMailbox.getChatContacts(getId());
if( contacts.length==1 ) {
name = MrMailbox.getContact(contacts[0]).getNameNAddr();
}
}
return name;
}
}
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,6 @@
*******************************************************************************
*
* File: MrChatlist.java
* Authors: Björn Petersen
* Purpose: Wrap around mrchatlist_t
*
******************************************************************************/
@@ -48,7 +47,7 @@ public class MrChatlist {
}
public MrPoortext getSummaryByIndex(int index, MrChat chat) {
return new MrPoortext(MrChatlistGetSummaryByIndex(m_hChatlist, index, chat.GetCPtr()));
return new MrPoortext(MrChatlistGetSummaryByIndex(m_hChatlist, index, chat.getCPtr()));
}
private long m_hChatlist;
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,6 @@
*******************************************************************************
*
* File: MrContact.java
* Authors: Björn Petersen
* Purpose: Wrap around mrcontact_t
*
******************************************************************************/
@@ -32,6 +31,7 @@ package com.b44t.messenger;
public class MrContact {
public final static int MR_CONTACT_ID_SELF = 1;
public final static int MR_CONTACT_ID_LAST_SPECIAL = 9;
public MrContact(long hContact) {
m_hContact = hContact;
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,6 @@
*******************************************************************************
*
* File: MrMailbox.java
* Authors: Björn Petersen
* Purpose: Wrap around mrmailbox_t
*
******************************************************************************/
@@ -29,86 +28,56 @@
package com.b44t.messenger;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import com.b44t.ui.Components.ForegroundDetector;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MrMailbox {
public static void init () {
m_hMailbox = MrMailboxNew();
}
public static int open(String dbfile, String blobdir) {
return MrMailboxOpen(m_hMailbox, dbfile, blobdir);
}
public native static int open(String dbfile);
public native static void close();
public native static String getBlobdir();
public static void close() {
MrMailboxClose(m_hMailbox);
}
public native static void configureAndConnect();
public native static void configureCancel();
public static int configure() {
return MrMailboxConfigure(m_hMailbox);
}
public native static int isConfigured();
public static int isConfigured() {
return MrMailboxIsConfigured(m_hMailbox);
}
public native static void connect();
public native static void disconnect();
public static int connect() {
return MrMailboxConnect(m_hMailbox);
}
public native static void setConfig(String key, String value);
public native static void setConfigInt(String key, int value);
public native static String getConfig(String key, String def);
public native static int getConfigInt(String key, int def);
public static void disconnect() {
MrMailboxDisconnect(m_hMailbox);
}
public static int fetch() {
return MrMailboxFetch(m_hMailbox);
}
public native static String getErrorDescr();
public static int setConfig(String key, String value) {
return MrMailboxSetConfig(m_hMailbox, key, value);
}
public static String getConfig(String key, String def) {
return MrMailboxGetConfig(m_hMailbox, key, def);
}
public static int getConfigInt(String key, int def) {
return MrMailboxGetConfigInt(m_hMailbox, key, def);
}
public static String getInfo() {
return MrMailboxGetInfo(m_hMailbox);
}
public static String execute(String cmd) {
return MrMailboxExecute(m_hMailbox, cmd);
}
public native static String getInfo();
public native static String cmdline(String cmd);
public native static void heartbeat();
private static long m_hMailbox = 0; // do not rename this, is used in C-part
private native static long MrMailboxNew (); // returns hMailbox which must be unref'd after usage (Names as mrmailbox_new don't work due to the additional underscore)
private native static int MrMailboxOpen (long hMailbox, String dbfile, String blobdir);
private native static void MrMailboxClose (long hMailbox);
private native static int MrMailboxConfigure (long hMailbox);
private native static int MrMailboxIsConfigured (long hMailbox);
private native static int MrMailboxConnect (long hMailbox);
private native static void MrMailboxDisconnect (long hMailbox);
private native static int MrMailboxFetch (long hMailbox);
private native static int MrMailboxSetConfig (long hMailbox, String key, String value); // value may be NULL
private native static String MrMailboxGetConfig (long hMailbox, String key, String def); // def may be NULL, returns empty string as NULL
private native static int MrMailboxGetConfigInt (long hMailbox, String key, int def); // def may be NULL, returns empty string as NULL
private native static String MrMailboxGetInfo (long hMailbox);
private native static String MrMailboxExecute (long hMailbox, String cmd);
private native static long MrMailboxNew(); // returns hMailbox which must be unref'd after usage (Names as mrmailbox_new don't work due to the additional underscore)
// contacts
public static int[] getKnownContacts(String query) {
return MrMailboxGetKnownContacts(m_hMailbox, query);
}
public static int[] getBlockedContacts() {
return MrMailboxGetBlockedContacts(m_hMailbox);
}
public native static int[] getKnownContacts(String query);
public native static int getBlockedCount();
public native static int[] getBlockedContacts();
public static MrContact getContact(int contact_id) {
return new MrContact(MrMailboxGetContact(m_hMailbox, contact_id));
@@ -130,8 +99,6 @@ public class MrMailbox {
return MrMailboxAddAddressBook(m_hMailbox, adrbook);
}
private native static int[] MrMailboxGetKnownContacts (long hMailbox, String query);
private native static int[] MrMailboxGetBlockedContacts(long hMailbox);
private native static long MrMailboxGetContact (long hMailbox, int id);// returns hContact which must be unref'd after usage
private native static int MrMailboxCreateContact (long hMailbox, String name, String addr);
private native static int MrMailboxBlockContact (long hMailbox, int id, int block);
@@ -140,53 +107,40 @@ public class MrMailbox {
// chats
public static MrChatlist getChatlist() {
return new MrChatlist(MrMailboxGetChatlist(m_hMailbox));
public static MrChatlist getChatlist(String query) {
return new MrChatlist(MrMailboxGetChatlist(m_hMailbox, query));
}
public static MrChat getChat(int contact_id) {
return new MrChat(MrMailboxGetChat(m_hMailbox, contact_id));
public static MrChat getChat(int chat_id) {
return new MrChat(MrMailboxGetChat(m_hMailbox, chat_id));
}
public native static int markseenMsg(int id); // TODO: needs to be implemented
public native static int markseenMsg (int msg_id);
public native static int markseenChat (int chat_id);
public static int markseenChat(int id) {
return MrMailboxMarkseenChat(m_hMailbox, id);
}
public native static int getChatIdByContactId (int contact_id);
public native static int createChatByContactId(int contact_id); // returns chat_id
public static int getChatIdByContactId (int contact_id) {
return MrMailboxGetChatIdByContactId(m_hMailbox, contact_id);
}
public native static int createGroupChat (String name);
public native static int isContactInChat (int chat_id, int contact_id);
public native static int addContactToChat (int chat_id, int contact_id);
public native static int removeContactFromChat (int chat_id, int contact_id);
public native static int setChatName (int chat_id, String name);
public static int createChatByContactId(int contact_id) {
return MrMailboxCreateChatByContactId(m_hMailbox, contact_id);
}
public final static int MR_GCM_ADDDAYMARKER = 0x01;
public native static int[] getChatMsgs(int chat_id, int flags, int marker1before);
public static int[] getChatMsgs(int chat_id) {
return MrMailboxGetChatMsgs(m_hMailbox, chat_id);
}
public native static int[] searchMsgs(int chat_id, String query);
public static int[] getChatMedia(int chat_id, int msg_type, int or_msg_type) {
return MrMailboxGetChatMedia(m_hMailbox, chat_id, msg_type, or_msg_type);
}
public native static int[] getUnseenMsgs();
public static int[] getChatContacts(int chat_id) {
return MrMailboxGetChatContacts(m_hMailbox, chat_id);
}
public native static int[] getChatMedia(int chat_id, int msg_type, int or_msg_type);
public native static int getNextMedia(int msg_id, int dir);
public native static int[] getChatContacts(int chat_id);
public native static int deleteChat(int chat_id);
public static int deleteChat(int chat_id) {
return MrMailboxDeleteChat(m_hMailbox, chat_id);
}
private native static long MrMailboxGetChatlist (long hMailbox); // returns hChatlist which must be unref'd after usage
private native static long MrMailboxGetChatlist (long hMailbox, String query); // returns hChatlist which must be unref'd after usage
private native static long MrMailboxGetChat (long hMailbox, int chat_id); // return hChat which must be unref'd after usage
private native static int MrMailboxMarkseenChat (long hMailbox, int id);
private native static int MrMailboxGetChatIdByContactId (long hMailbox, int contact_id);
private native static int MrMailboxCreateChatByContactId(long hMailbox, int contact_id); // returns chat_id
private native static int[] MrMailboxGetChatMsgs (long hMailbox, int chat_id);
private native static int[] MrMailboxGetChatMedia (long hMailbox, int chat_id, int msg_type, int or_msg_type);
private native static int[] MrMailboxGetChatContacts (long hMailbox, int chat_id);
private native static int MrMailboxDeleteChat (long hMailbox, int chat_id);
// msgs
@@ -198,46 +152,79 @@ public class MrMailbox {
return MrMailboxGetMsgInfo(m_hMailbox, id);
}
public static void deleteMsg(int id) {
MrMailboxDeleteMsg(m_hMailbox, id);
}
public native static void deleteMsgs(int msg_ids[]);
public native static void forwardMsgs(int msg_ids[], int chat_ids);
private native static long MrMailboxGetMsg (long hMailbox, int id); // return hMsg which must be unref'd after usage
private native static String MrMailboxGetMsgInfo (long hMailbox, int id);
private native static void MrMailboxDeleteMsg (long hMailbox, int id);
// static
public native static void MrStockAddStr (int id, String str);
public native static String MrGetVersionStr ();
public native static String CPtr2String (long hString); // get strings eg. from data1 from the callback
public native static long String2CPtr (String str);
/* receive events
**********************************************************************************************/
public final static int MR_EVENT_MSGS_UPDATED = 2000;
public final static int MR_EVENT_INFO = 100;
public final static int MR_EVENT_WARNING = 300;
public final static int MR_EVENT_ERROR = 400; // INFO and WARNING are blocked in the mrwrapper.c
public final static int MR_EVENT_MSGS_CHANGED = 2000;
public final static int MR_EVENT_INCOMING_MSG = 2005;
public final static int MR_EVENT_MSG_DELIVERED = 2010;
public final static int MR_EVENT_MSG_READ = 2015;
public final static int MR_EVENT_CHAT_MODIFIED = 2020;
public final static int MR_EVENT_CONTACTS_CHANGED = 2030;
public final static int MR_EVENT_MSG_DELIVERED = 3000;
public final static int MR_EVENT_MSG_READ = 3010;
public final static int MR_EVENT_CONNECTION_STATE_CHANGED = 3020;
public final static int MR_EVENT_CONFIGURE_ENDED = 2040;
public final static int MR_EVENT_CONFIGURE_PROGRESS = 2041;
public final static int MR_EVENT_IS_ONLINE = 2080;
public final static int MR_EVENT_GET_STRING = 2091;
public final static int MR_EVENT_GET_QUANTITIY_STRING = 2092;
public final static int MR_EVENT_HTTP_GET = 2100;
public final static int MR_EVENT_WAKE_LOCK = 2110;
public static final Object m_lastErrorLock = new Object();
public static int m_lastErrorCode = 0;
public static String m_lastErrorString = "";
public static boolean m_showNextErrorAsToast = true;
public static long MrCallback(final int event, final long data1, final long data2) // this function is called from within the C-wrapper
{
switch(event) {
case MR_EVENT_CONNECTION_STATE_CHANGED:
case MR_EVENT_CONFIGURE_ENDED:
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.connectionStateChanged, (int)data1);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.configureEnded, (int)data1);
}
});
return 0;
case MR_EVENT_MSGS_UPDATED:
case MR_EVENT_CONFIGURE_PROGRESS:
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.getInstance().postNotificationName(NotificationCenter.configureProgress, (int)data1);
}
});
return 0;
case MR_EVENT_MSGS_CHANGED:
case MR_EVENT_INCOMING_MSG:
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
reloadMainChatlist();
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload, event, (int)data1, (int)data2);
if( event == MR_EVENT_INCOMING_MSG ) {
NotificationsController.getInstance().processNewMessages((int)data1, (int)data2);
}
}
});
return 0;
@@ -265,6 +252,128 @@ public class MrMailbox {
}
});
return 0;
case MR_EVENT_CHAT_MODIFIED:
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
reloadMainChatlist();
NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces,
UPDATE_MASK_NAME|UPDATE_MASK_CHAT_NAME|
UPDATE_MASK_CHAT_MEMBERS|UPDATE_MASK_AVATAR);
}
});
return 0;
case MR_EVENT_INFO:
Log.i("DeltaChat", CPtr2String(data2));
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
FileLog.i("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
}
break;
case MR_EVENT_WARNING:
Log.w("DeltaChat", CPtr2String(data2));
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
FileLog.w("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
}
break;
case MR_EVENT_ERROR:
Log.e("DeltaChat", CPtr2String(data2));
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
FileLog.e("DeltaChat", CPtr2String(data2)); // TODO: Can be removed as soon as notifications are reliable.
}
synchronized (m_lastErrorLock) {
m_lastErrorCode = (int)data1;
m_lastErrorString = CPtr2String(data2);
}
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
synchronized (m_lastErrorLock) {
if( m_showNextErrorAsToast ) {
if(ForegroundDetector.getInstance().isForeground()) {
AndroidUtilities.showHint(ApplicationLoader.applicationContext, m_lastErrorString);
}
}
m_showNextErrorAsToast = true;
}
}
});
return 0;
case MR_EVENT_GET_STRING:
String s = "ErrStrBadId";
switch( (int)data1 ) {
// the string-IDs are defined in the backend; as this is the only place where they're used, there is no benefit in creating an enum or sth. like that.
case 1: s = ApplicationLoader.applicationContext.getString(R.string.NoMessages); break;
case 2: s = ApplicationLoader.applicationContext.getString(R.string.FromSelf); break;
case 3: s = ApplicationLoader.applicationContext.getString(R.string.Draft); break;
case 7: s = ApplicationLoader.applicationContext.getString(R.string.AttachVoiceMessage); break;
case 8: s = ApplicationLoader.applicationContext.getString(R.string.Deaddrop); break;
case 9: s = ApplicationLoader.applicationContext.getString(R.string.AttachPhoto); break;
case 10: s = ApplicationLoader.applicationContext.getString(R.string.AttachVideo); break;
case 11: s = ApplicationLoader.applicationContext.getString(R.string.Audio); break;
case 12: s = ApplicationLoader.applicationContext.getString(R.string.AttachDocument); break;
case 13: s = ApplicationLoader.applicationContext.getString(R.string.DefaultStatusText); break;
case 14: s = ApplicationLoader.applicationContext.getString(R.string.MsgNewGroupDraft); break;
case 15: s = ApplicationLoader.applicationContext.getString(R.string.MsgGroupNameChanged); break;
case 16: s = ApplicationLoader.applicationContext.getString(R.string.MsgGroupImageChanged); break;
case 17: s = ApplicationLoader.applicationContext.getString(R.string.MsgMemberAddedToGroup); break;
case 18: s = ApplicationLoader.applicationContext.getString(R.string.MsgMemberRemovedFromToGroup); break;
case 19: s = ApplicationLoader.applicationContext.getString(R.string.MsgGroupLeft); break;
case 20: s = ApplicationLoader.applicationContext.getString(R.string.Error); break;
case 21: s = ApplicationLoader.applicationContext.getString(R.string.ErrSelfNotInGroup); break;
case 22: s = ApplicationLoader.applicationContext.getString(R.string.NoNetwork); break;
}
return String2CPtr(s);
case MR_EVENT_GET_QUANTITIY_STRING:
String sp = "ErrQtyStrBadId";
switch( (int)data1 ) {
// the string-IDs are defined in the backend; as this is the only place where they're used, there is no benefit in creating an enum or sth. like that.
case 4: sp = ApplicationLoader.applicationContext.getResources().getQuantityString(R.plurals.Members, (int)data2, (int)data2); break;
case 6: sp = ApplicationLoader.applicationContext.getResources().getQuantityString(R.plurals.Contacts, (int)data2, (int)data2); break;
}
return String2CPtr(sp);
case MR_EVENT_IS_ONLINE:
return ApplicationLoader.isNetworkOnline()? 1 : 0;
case MR_EVENT_HTTP_GET:
String httpContent = null;
try {
URL url = new URL(CPtr2String(data1));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
httpContent = total.toString();
} finally {
urlConnection.disconnect();
}
}
catch(Exception e) {}
return String2CPtr(httpContent);
case MR_EVENT_WAKE_LOCK:
if( data1 != 0 ) {
ApplicationLoader.backendWakeLock.acquire();
}
else {
if( !ApplicationLoader.wakeupWakeLock.isHeld()) {
ApplicationLoader.wakeupWakeLock.acquire(1 * 1000); /* make sure, subsequent release/acquires do not make the CPU sleep */
}
ApplicationLoader.backendWakeLock.release();
}
return 0;
}
return 0;
}
@@ -273,10 +382,83 @@ public class MrMailbox {
/* additional functions that are not 1:1 available in the backend
**********************************************************************************************/
public static void log_i(String tag, String msg)
{
Log.i(tag, msg);
if( BuildConfig.BUILD_TYPE.equals("debug") ) {
FileLog.i(tag, msg); // TODO: Can be removed as soon as notifications are reliable.
}
}
public static MrChatlist m_currChatlist = new MrChatlist(0);
public native static int getCurrentTime ();
public static void reloadMainChatlist()
{
m_currChatlist = getChatlist();
m_currChatlist = getChatlist(null);
}
public final static int MEDIA_PHOTOVIDEO = 0;
public static void getMediaCount(final long uid, final int type, final int classGuid, boolean fromCache) {
Utilities.globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
int[] media = new int[0];
if( type == MEDIA_PHOTOVIDEO ) {
media = MrMailbox.getChatMedia((int)uid, MrMsg.MR_MSG_IMAGE, MrMsg.MR_MSG_VIDEO);
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.mediaCountDidLoaded,
uid, media.length, false /*not from cache*/, type, media);
}
});
}
public static String getInviteText() {
String url = "https://getdelta.org";
String email = getConfig("addr", "");
String text = LocaleController.formatString("InviteText", R.string.InviteText, url, email);
return text;
}
public static TLRPC.User getUser(Integer id) {
TLRPC.User u = new TLRPC.User(); // legacy function, information should be loaded as needed by the caller
u.id = id;
return u;
}
public static void cancelTyping(int action, long dialog_id) {
}
public static void sendTyping(final long dialog_id, final int action, int classGuid) {
}
public static void markMessageContentAsRead(final MessageObject messageObject) {
}
public static boolean isDialogMuted(long dialog_id) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
int mute_type = preferences.getInt("notify2_" + dialog_id, 0);
if (mute_type == 2) {
return true;
} else if (mute_type == 3) {
int mute_until = preferences.getInt("notifyuntil_" + dialog_id, 0);
if (mute_until >= MrMailbox.getCurrentTime()) {
return true;
}
}
return false;
}
// legacy update masks
public static final int UPDATE_MASK_NAME = 1;
public static final int UPDATE_MASK_AVATAR = 2;
public static final int UPDATE_MASK_STATUS = 4;
public static final int UPDATE_MASK_CHAT_AVATAR = 8;
public static final int UPDATE_MASK_CHAT_NAME = 16;
public static final int UPDATE_MASK_CHAT_MEMBERS = 32;
public static final int UPDATE_MASK_SELECT_DIALOG = 512;
public static final int UPDATE_MASK_NEW_MESSAGE = 2048;
public static final int UPDATE_MASK_SEND_STATE = 4096;
}
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,6 @@
*******************************************************************************
*
* File: MrMsg.java
* Authors: Björn Petersen
* Purpose: Wrap around mrmsg_t
*
******************************************************************************/
@@ -28,12 +27,22 @@
package com.b44t.messenger;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.provider.MediaStore;
import android.util.Log;
import java.io.File;
public class MrMsg {
private static final String TAG = "MrMsg";
public final static int MR_MSG_UNDEFINED = 0;
public final static int MR_MSG_TEXT = 10;
public final static int MR_MSG_IMAGE = 20;
public final static int MR_MSG_AUDIO = 40;
public final static int MR_MSG_VOICE = 41;
public final static int MR_MSG_VIDEO = 50;
public final static int MR_MSG_FILE = 60;
@@ -46,6 +55,9 @@ public class MrMsg {
public final static int MR_OUT_DELIVERED = 26;
public final static int MR_OUT_READ = 28;
public final static int MR_MSG_ID_MARKER1 = 1;
public final static int MR_MSG_ID_DAYMARKER = 9;
public MrMsg(long hMsg) {
m_hMsg = hMsg;
}
@@ -84,14 +96,21 @@ public class MrMsg {
return MrMsgGetToId(m_hMsg);
}
public String getParam (int key, String def) {
return MrMsgGetParam(m_hMsg, key, def);
}
public int getParamInt(int key, int def) {
return MrMsgGetParamInt(m_hMsg, key, def);
}
public native String getParam(int key, String def);
public native int getParamInt(int key, int def);
public native void setParamInt(int key, int def);
public native void saveParamToDisk();
private long m_hMsg;
public native int getBytes();
public MrPoortext getSummary(MrChat chat) { return new MrPoortext(getSummaryCPtr(chat.getCPtr())); }
private native long getSummaryCPtr(long hChat);
public native String getSummarytext(int approx_characters);
public MrPoortext getMediainfo() { return new MrPoortext(getMediainfoCPtr()); }
private native long getMediainfoCPtr();
public native String getFilename();
public native int isIncreation();
private long m_hMsg; // must not be renamed as referenced by JNI under the name "m_hMsg"
private native static void MrMsgUnref (long hMsg);
private native static int MrMsgGetId (long hMsg);
private native static String MrMsgGetText (long hMsg);
@@ -101,8 +120,6 @@ public class MrMsg {
private native static int MrMsgGetChatId (long hMsg);
private native static int MrMsgGetFromId (long hMsg);
private native static int MrMsgGetToId (long hMsg);
private native static String MrMsgGetParam (long hMsg, int key, String def);
private native static int MrMsgGetParamInt (long hMsg, int key, int def);
/* additional functions that are not 1:1 available in the backend
@@ -132,7 +149,6 @@ public class MrMsg {
ret.unread = state!=MR_OUT_READ; // the state of outgoing messages
ret.media_unread = ret.unread;
ret.flags = 0; // posible flags: MESSAGE_FLAG_HAS_FROM_ID, however, this seems to be read only
ret.post = false; // ? true=avatar wird in gruppen nicht angezeigt, wird aber in isFromUser() auch überprüft...
ret.out = ret.from_id==MrContact.MR_CONTACT_ID_SELF; // true=outgoing message, read eg. in MessageObject.isOutOwner()
ret.created_by_mr = true;
@@ -147,11 +163,21 @@ public class MrMsg {
TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize();
photoSize.w = getParamInt('w', 800);
photoSize.h = getParamInt('h', 800);
photoSize.size = 0;
photoSize.size = 0; // not sure what to use here, maybe `getBytes();`?
photoSize.location = new TLRPC.TL_fileLocation();
photoSize.location.mr_path = path;
photoSize.location.local_id = -ret.id; // this forces the document to be searched in the cache dir
photoSize.type = "x";
if (photoSize.w <= 100 && photoSize.h <= 100) {
photoSize.type = "s";
} else if (photoSize.w <= 320 && photoSize.h <= 320) {
photoSize.type = "m";
} else if (photoSize.w <= 800 && photoSize.h <= 800) {
photoSize.type = "x";
} else if (photoSize.w <= 1280 && photoSize.h <= 1280) {
photoSize.type = "y";
} else {
photoSize.type = "w";
}
photo = new TLRPC.TL_photo();
photo.sizes.add(photoSize);
} catch (Exception e) {
@@ -169,37 +195,78 @@ public class MrMsg {
ret.message = "<cannot load image>";
}
}
else if( type == MR_MSG_AUDIO || type == MR_MSG_VIDEO ) {
else if( type == MR_MSG_AUDIO || type == MR_MSG_VOICE || type == MR_MSG_VIDEO || type == MR_MSG_FILE ) {
String path = getParam('f', "");
if( !path.isEmpty()) {
ret.message = "-1"; // may be misused for video editing information
ret.media = new TLRPC.TL_messageMediaDocument();
ret.media.caption = "";
ret.media.document = new TLRPC.TL_document();
ret.media.document.file_name = getFilename();
ret.media.document.mr_path = path;
if( type == MR_MSG_AUDIO ) {
ret.media.document.size = getBytes();
if( type == MR_MSG_AUDIO || type == MR_MSG_VOICE ) {
TLRPC.TL_documentAttributeAudio attr = new TLRPC.TL_documentAttributeAudio();
attr.voice = true; // !voice = music
attr.voice = type == MR_MSG_VOICE;
attr.duration = getParamInt('d', 0) / 1000;
ret.media.document.attributes.add(attr);
}
else if( type == MR_MSG_VIDEO) {
else if( type == MR_MSG_VIDEO ) {
File vfile = new File(path);
File tfile = new File(MrMailbox.getBlobdir(), vfile.getName()+"-preview.jpg");
if( !tfile.exists() ) {
try {
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND);
TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(tfile, thumb, 90, 90, 55, false);
size.location.mr_path = tfile.getAbsolutePath();
size.type = "s";
ret.media.document.thumb = size;
setParamInt('w', size.w);
setParamInt('h', size.h);
saveParamToDisk();
}
catch (Exception e) {}
}
else {
TLRPC.PhotoSize size = new TLRPC.PhotoSize();
size.location = new TLRPC.TL_fileLocation();
size.location.mr_path = tfile.getAbsolutePath();
size.location.local_id = -ret.id;
size.w = getParamInt('w', 320);
size.h = getParamInt('h', 240);
size.type = "s";
ret.media.document.thumb = size;
}
TLRPC.TL_documentAttributeVideo attr = new TLRPC.TL_documentAttributeVideo();
attr.duration = getParamInt('d', 0) / 1000;
attr.w = getParamInt('w', 0);
attr.h = getParamInt('h', 0);
attr.w = getParamInt('w', 320);
attr.h = getParamInt('h', 240);
ret.media.document.attributes.add(attr);
}
else {
ret.media.document.mime_type = getParam('m', "application/octet-stream");
}
}
else {
ret.message = "<path missing>";
ret.message = "<file path missing>";
}
}
else {
ret.message = String.format("<unsupported message type #%d for id #%d>", type, ret.id);
}
if( !getParam('a', "").equals("") ) {
ret.flags |= TLRPC.MESSAGE_FLAG_FWD;
ret.fwd_from = new TLRPC.TL_messageFwdHeader();
ret.fwd_from.m_name = getParam('A', "");
if( ret.fwd_from.m_name.isEmpty() ) {
ret.fwd_from.m_name = getParam('a', "");
}
}
return ret;
}
};
@@ -1,8 +1,8 @@
/*******************************************************************************
*
* Messenger Android Frontend
* Copyright (C) 2016 Björn Petersen Software Design and Development
* Contact: r10s@b44t.com, http://b44t.com
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,6 @@
*******************************************************************************
*
* File: MrPoortext.java
* Authors: Björn Petersen
* Purpose: Wrap around mrpoortext_t
*
******************************************************************************/
@@ -31,10 +30,10 @@ package com.b44t.messenger;
public class MrPoortext {
public final static int MR_TITLE_NORMAL = 0;
public final static int MR_TITLE_DRAFT = 1;
public final static int MR_TITLE_USERNAME = 2;
public final static int MR_TITLE_SELF = 3;
public final static int MR_TEXT1_NORMAL = 0;
public final static int MR_TEXT1_DRAFT = 1;
public final static int MR_TEXT1_USERNAME = 2;
public final static int MR_TEXT1_SELF = 3;
public MrPoortext(long hPoortext) {
m_hPoortext = hPoortext;
@@ -45,16 +44,16 @@ public class MrPoortext {
MrPoortextUnref(m_hPoortext);
}
public String getTitle() {
return MrPoortextGetTitle(m_hPoortext);
public String getText1() {
return MrPoortextGetText1(m_hPoortext);
}
public int getTitleMeaning() {
return MrPoortextGetTitleMeaning(m_hPoortext);
public int getText1Meaning() {
return MrPoortextGetText1Meaning(m_hPoortext);
}
public String getText() {
return MrPoortextGetText(m_hPoortext);
public String getText2() {
return MrPoortextGetText2(m_hPoortext);
}
public long getTimestamp() {
@@ -67,9 +66,9 @@ public class MrPoortext {
private long m_hPoortext;
private native static void MrPoortextUnref (long hPoortext);
private native static String MrPoortextGetTitle (long hPoortext);
private native static int MrPoortextGetTitleMeaning (long hPoortext);
private native static String MrPoortextGetText (long hPoortext);
private native static String MrPoortextGetText1 (long hPoortext);
private native static int MrPoortextGetText1Meaning (long hPoortext);
private native static String MrPoortextGetText2 (long hPoortext);
private native static long MrPoortextGetTimestamp (long hPoortext);
private native static int MrPoortextGetState (long hPoortext);
}
@@ -1,589 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.os.SystemClock;
import android.service.media.MediaBrowserService;
import com.b44t.messenger.audioinfo.AudioInfo;
import com.b44t.ui.LaunchActivity;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MusicBrowserService extends MediaBrowserService implements NotificationCenter.NotificationCenterDelegate {
private static final String AUTO_APP_PACKAGE_NAME = "com.google.android.projection.gearhead";
private static final String SLOT_RESERVATION_SKIP_TO_NEXT = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
private static final String SLOT_RESERVATION_SKIP_TO_PREV = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
private static final String SLOT_RESERVATION_QUEUE = "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_QUEUE";
private MediaSession mediaSession;
private static final String MEDIA_ID_ROOT = "__ROOT__";
private boolean chatsLoaded;
private boolean loadingChats;
private ArrayList<Integer> dialogs = new ArrayList<>();
private HashMap<Integer, TLRPC.User> users = new HashMap<>();
private HashMap<Integer, TLRPC.Chat> chats = new HashMap<>();
private HashMap<Integer, ArrayList<MessageObject>> musicObjects = new HashMap<>();
private HashMap<Integer, ArrayList<MediaSession.QueueItem>> musicQueues = new HashMap<>();
public static final String ACTION_CMD = "com.example.android.mediabrowserservice.ACTION_CMD";
public static final String CMD_NAME = "CMD_NAME";
public static final String CMD_PAUSE = "CMD_PAUSE";
private Paint roundPaint;
private RectF bitmapRect;
private boolean serviceStarted;
private int lastSelectedDialog;
private static final int STOP_DELAY = 30000;
private DelayedStopHandler delayedStopHandler = new DelayedStopHandler(this);
@Override
public void onCreate() {
super.onCreate();
ApplicationLoader.postInitApplication();
lastSelectedDialog = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getInt("auto_lastSelectedDialog", 0);
mediaSession = new MediaSession(this, "MusicService");
setSessionToken(mediaSession.getSessionToken());
mediaSession.setCallback(new MediaSessionCallback());
mediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
Context context = getApplicationContext();
Intent intent = new Intent(context, LaunchActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 99, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mediaSession.setSessionActivity(pi);
Bundle extras = new Bundle();
extras.putBoolean(SLOT_RESERVATION_QUEUE, true);
extras.putBoolean(SLOT_RESERVATION_SKIP_TO_PREV, true);
extras.putBoolean(SLOT_RESERVATION_SKIP_TO_NEXT, true);
mediaSession.setExtras(extras);
updatePlaybackState(null);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidStarted);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset);
}
@Override
public int onStartCommand(Intent startIntent, int flags, int startId) {
/*if (startIntent != null) {
String action = startIntent.getAction();
String command = startIntent.getStringExtra(CMD_NAME);
if (ACTION_CMD.equals(action)) {
if (CMD_PAUSE.equals(command)) {
if (mPlayback != null && mPlayback.isPlaying()) {
handlePauseRequest();
}
}
}
}*/
return START_STICKY;
}
@Override
public void onDestroy() {
handleStopRequest(null);
delayedStopHandler.removeCallbacksAndMessages(null);
mediaSession.release();
}
@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
if (clientPackageName == null || Process.SYSTEM_UID != clientUid && Process.myUid() != clientUid && !clientPackageName.equals("com.google.android.mediasimulator") && !clientPackageName.equals("com.google.android.projection.gearhead")) {
return null;
}
return new BrowserRoot(MEDIA_ID_ROOT, null);
}
@Override
public void onLoadChildren(final String parentMediaId, final Result<List<MediaBrowser.MediaItem>> result) {
if (!chatsLoaded) {
result.detach();
if (loadingChats) {
return;
}
loadingChats = true;
/*
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
@Override
public void run() {
try {
ArrayList<Integer> usersToLoad = new ArrayList<>();
ArrayList<Integer> chatsToLoad = new ArrayList<>();
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT DISTINCT uid FROM media_v2 WHERE uid != 0 AND mid > 0 AND type = %d", SharedMediaQuery.MEDIA_MUSIC));
while (cursor.next()) {
int lower_part = (int) cursor.longValue(0);
if (lower_part == 0) {
continue;
}
dialogs.add(lower_part);
if (lower_part > 0) {
usersToLoad.add(lower_part);
} else {
chatsToLoad.add(-lower_part);
}
}
cursor.dispose();
if (!dialogs.isEmpty()) {
String ids = TextUtils.join(",", dialogs);
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT uid, data, mid FROM media_v2 WHERE uid IN (%s) AND mid > 0 AND type = %d ORDER BY date DESC, mid DESC", ids, SharedMediaQuery.MEDIA_MUSIC));
while (cursor.next()) {
NativeByteBuffer data = cursor.byteBufferValue(1);
if (data != null) {
TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false);
data.reuse();
if (MessageObject.isMusicMessage(message)) {
int did = cursor.intValue(0);
message.id = cursor.intValue(2);
message.dialog_id = did;
ArrayList<MessageObject> arrayList = musicObjects.get(did);
ArrayList<MediaSession.QueueItem> arrayList1 = musicQueues.get(did);
if (arrayList == null) {
arrayList = new ArrayList<>();
musicObjects.put(did, arrayList);
arrayList1 = new ArrayList<>();
musicQueues.put(did, arrayList1);
}
MessageObject messageObject = new MessageObject(message, null, false);
arrayList.add(0, messageObject);
MediaDescription.Builder builder = new MediaDescription.Builder().setMediaId(did + "_" + arrayList.size());
builder.setTitle(messageObject.getMusicTitle());
builder.setSubtitle(messageObject.getMusicAuthor());
arrayList1.add(0, new MediaSession.QueueItem(builder.build(), arrayList1.size()));
}
}
}
cursor.dispose();
if (!usersToLoad.isEmpty()) {
ArrayList<TLRPC.User> usersArrayList = new ArrayList<>();
//MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), usersArrayList);
for (int a = 0; a < usersArrayList.size(); a++) {
TLRPC.User user = usersArrayList.get(a);
users.put(user.id, user);
}
}
if (!chatsToLoad.isEmpty()) {
ArrayList<TLRPC.Chat> chatsArrayList = new ArrayList<>();
//MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chatsArrayList);
for (int a = 0; a < chatsArrayList.size(); a++) {
TLRPC.Chat chat = chatsArrayList.get(a);
chats.put(chat.id, chat);
}
}
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
AndroidUtilities.runOnUIThread(new Runnable() {
@Override
public void run() {
chatsLoaded = true;
loadingChats = false;
loadChildrenImpl(parentMediaId, result);
if (lastSelectedDialog == 0 && !dialogs.isEmpty()) {
lastSelectedDialog = dialogs.get(0);
}
if (lastSelectedDialog != 0) {
ArrayList<MessageObject> arrayList = musicObjects.get(lastSelectedDialog);
ArrayList<MediaSession.QueueItem> arrayList1 = musicQueues.get(lastSelectedDialog);
if (arrayList != null && !arrayList.isEmpty()) {
mediaSession.setQueue(arrayList1);
if (lastSelectedDialog > 0) {
TLRPC.User user = users.get(lastSelectedDialog);
if (user != null) {
mediaSession.setQueueTitle(ContactsController.formatName(user.first_name, user.last_name));
} else {
mediaSession.setQueueTitle("DELETED USER");
}
} else {
TLRPC.Chat chat = chats.get(-lastSelectedDialog);
if (chat != null) {
mediaSession.setQueueTitle(chat.title);
} else {
mediaSession.setQueueTitle("DELETED CHAT");
}
}
MessageObject messageObject = arrayList.get(0);
MediaMetadata.Builder builder = new MediaMetadata.Builder();
builder.putLong(MediaMetadata.METADATA_KEY_DURATION, messageObject.getDuration() * 1000);
builder.putString(MediaMetadata.METADATA_KEY_ARTIST, messageObject.getMusicAuthor());
builder.putString(MediaMetadata.METADATA_KEY_TITLE, messageObject.getMusicTitle());
mediaSession.setMetadata(builder.build());
}
}
updatePlaybackState(null);
}
});
}
});
*/
} else {
loadChildrenImpl(parentMediaId, result);
}
}
private void loadChildrenImpl(final String parentMediaId, final Result<List<MediaBrowser.MediaItem>> result) {
List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();
if (MEDIA_ID_ROOT.equals(parentMediaId)) {
for (int a = 0; a < dialogs.size(); a++) {
int did = dialogs.get(a);
MediaDescription.Builder builder = new MediaDescription.Builder().setMediaId("__CHAT_" + did);
TLRPC.FileLocation avatar = null;
if (did > 0) {
TLRPC.User user = users.get(did);
if (user != null) {
builder.setTitle(ContactsController.formatName(user.first_name, user.last_name));
if (user.photo != null && user.photo.photo_small instanceof TLRPC.TL_fileLocation) {
avatar = user.photo.photo_small;
}
} else {
builder.setTitle("DELETED USER");
}
} else {
TLRPC.Chat chat = chats.get(-did);
if (chat != null) {
builder.setTitle(chat.title);
if (chat.photo != null && chat.photo.photo_small instanceof TLRPC.TL_fileLocation) {
avatar = chat.photo.photo_small;
}
} else {
builder.setTitle("DELETED CHAT");
}
}
Bitmap bitmap = null;
if (avatar != null) {
bitmap = createRoundBitmap(FileLoader.getPathToAttach(avatar, true));
if (bitmap != null) {
builder.setIconBitmap(bitmap);
}
}
if (avatar == null || bitmap == null) {
builder.setIconUri(Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/drawable/contact_blue"));
}
mediaItems.add(new MediaBrowser.MediaItem(builder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE));
}
} else if (parentMediaId != null && parentMediaId.startsWith("__CHAT_")) {
int did = 0;
try {
did = Integer.parseInt(parentMediaId.replace("__CHAT_", ""));
} catch (Exception e) {
FileLog.e("messenger", e);
}
ArrayList<MessageObject> arrayList = musicObjects.get(did);
if (arrayList != null) {
for (int a = 0; a < arrayList.size(); a++) {
MessageObject messageObject = arrayList.get(a);
MediaDescription.Builder builder = new MediaDescription.Builder().setMediaId(did + "_" + a);
builder.setTitle(messageObject.getMusicTitle());
builder.setSubtitle(messageObject.getMusicAuthor());
mediaItems.add(new MediaBrowser.MediaItem(builder.build(), MediaBrowser.MediaItem.FLAG_PLAYABLE));
}
}
}
result.sendResult(mediaItems);
}
private Bitmap createRoundBitmap(File path) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(path.toString(), options);
if (bitmap != null) {
Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
result.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(result);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
if (roundPaint == null) {
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapRect = new RectF();
}
roundPaint.setShader(shader);
bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawRoundRect(bitmapRect, bitmap.getWidth(), bitmap.getHeight(), roundPaint);
return result;
}
} catch (Throwable e) {
FileLog.e("messenger", e);
}
return null;
}
private final class MediaSessionCallback extends MediaSession.Callback {
@Override
public void onPlay() {
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject == null) {
onPlayFromMediaId(lastSelectedDialog + "_" + 0, null);
} else {
MediaController.getInstance().playAudio(messageObject);
}
}
@Override
public void onSkipToQueueItem(long queueId) {
MediaController.getInstance().playMessageAtIndex((int) queueId);
handlePlayRequest();
}
@Override
public void onSeekTo(long position) {
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject != null) {
MediaController.getInstance().seekToProgress(messageObject, position / 1000 / (float) messageObject.getDuration());
}
}
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
String args[] = mediaId.split("_");
if (args.length != 2) {
return;
}
try {
int did = Integer.parseInt(args[0]);
int id = Integer.parseInt(args[1]);
ArrayList<MessageObject> arrayList = musicObjects.get(did);
ArrayList<MediaSession.QueueItem> arrayList1 = musicQueues.get(did);
if (arrayList == null || id < 0 || id >= arrayList.size()) {
return;
}
lastSelectedDialog = did;
ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).edit().putInt("auto_lastSelectedDialog", did).commit();
MediaController.getInstance().setPlaylist(arrayList, arrayList.get(id), false);
mediaSession.setQueue(arrayList1);
if (did > 0) {
TLRPC.User user = users.get(did);
if (user != null) {
mediaSession.setQueueTitle(ContactsController.formatName(user.first_name, user.last_name));
} else {
mediaSession.setQueueTitle("DELETED USER");
}
} else {
TLRPC.Chat chat = chats.get(-did);
if (chat != null) {
mediaSession.setQueueTitle(chat.title);
} else {
mediaSession.setQueueTitle("DELETED CHAT");
}
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
handlePlayRequest();
}
@Override
public void onPause() {
handlePauseRequest();
}
@Override
public void onStop() {
handleStopRequest(null);
}
@Override
public void onSkipToNext() {
MediaController.getInstance().playNextMessage();
}
@Override
public void onSkipToPrevious() {
MediaController.getInstance().playPreviousMessage();
}
@Override
public void onPlayFromSearch(String query, Bundle extras) {
if (query == null || query.length() == 0) {
return;
}
query = query.toLowerCase();
for (int a = 0; a < dialogs.size(); a++) {
int did = dialogs.get(a);
if (did > 0) {
TLRPC.User user = users.get(did);
if (user == null) {
continue;
}
if (user.first_name != null && user.first_name.startsWith(query) || user.last_name != null && user.last_name.startsWith(query)) {
onPlayFromMediaId(did + "_" + 0, null);
break;
}
} else {
TLRPC.Chat chat = chats.get(-did);
if (chat == null) {
continue;
}
if (chat.title != null && chat.title.toLowerCase().contains(query)) {
onPlayFromMediaId(did + "_" + 0, null);
break;
}
}
}
}
}
private void updatePlaybackState(String error) {
long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
MessageObject playingMessageObject = MediaController.getInstance().getPlayingMessageObject();
if (playingMessageObject != null) {
position = playingMessageObject.audioProgressSec * 1000;
}
PlaybackState.Builder stateBuilder = new PlaybackState.Builder().setActions(getAvailableActions());
int state;
if (playingMessageObject == null) {
state = PlaybackState.STATE_STOPPED;
} else {
if (MediaController.getInstance().isDownloadingCurrentMessage()) {
state = PlaybackState.STATE_BUFFERING;
} else {
state = MediaController.getInstance().isAudioPaused() ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING;
}
}
if (error != null) {
stateBuilder.setErrorMessage(error);
state = PlaybackState.STATE_ERROR;
}
stateBuilder.setState(state, position, 1.0f, SystemClock.elapsedRealtime());
if (playingMessageObject != null) {
stateBuilder.setActiveQueueItemId(MediaController.getInstance().getPlayingMessageObjectNum());
} else {
stateBuilder.setActiveQueueItemId(0);
}
mediaSession.setPlaybackState(stateBuilder.build());
}
private long getAvailableActions() {
long actions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PLAY_FROM_SEARCH;
MessageObject playingMessageObject = MediaController.getInstance().getPlayingMessageObject();
if (playingMessageObject != null) {
if (!MediaController.getInstance().isAudioPaused()) {
actions |= PlaybackState.ACTION_PAUSE;
}
actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
}
return actions;
}
private void handleStopRequest(String withError) {
delayedStopHandler.removeCallbacksAndMessages(null);
delayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
updatePlaybackState(withError);
stopSelf();
serviceStarted = false;
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidStarted);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset);
}
private void handlePlayRequest() {
delayedStopHandler.removeCallbacksAndMessages(null);
if (!serviceStarted) {
startService(new Intent(getApplicationContext(), MusicBrowserService.class));
serviceStarted = true;
}
if (!mediaSession.isActive()) {
mediaSession.setActive(true);
}
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject == null) {
return;
}
MediaMetadata.Builder builder = new MediaMetadata.Builder();
builder.putLong(MediaMetadata.METADATA_KEY_DURATION, messageObject.getDuration() * 1000);
builder.putString(MediaMetadata.METADATA_KEY_ARTIST, messageObject.getMusicAuthor());
builder.putString(MediaMetadata.METADATA_KEY_TITLE, messageObject.getMusicTitle());
AudioInfo audioInfo = MediaController.getInstance().getAudioInfo();
if (audioInfo != null) {
Bitmap bitmap = audioInfo.getCover();
if (bitmap != null) {
builder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap);
}
}
mediaSession.setMetadata(builder.build());
}
private void handlePauseRequest() {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
delayedStopHandler.removeCallbacksAndMessages(null);
delayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
}
@Override
public void didReceivedNotification(int id, Object... args) {
updatePlaybackState(null);
handlePlayRequest();
}
private static class DelayedStopHandler extends Handler {
private final WeakReference<MusicBrowserService> mWeakReference;
private DelayedStopHandler(MusicBrowserService service) {
mWeakReference = new WeakReference<>(service);
}
@Override
public void handleMessage(Message msg) {
MusicBrowserService service = mWeakReference.get();
if (service != null) {
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject != null && !MediaController.getInstance().isAudioPaused()) {
return;
}
service.stopSelf();
service.serviceStarted = false;
}
}
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -46,10 +61,10 @@ public class MusicPlayerReceiver extends BroadcastReceiver {
case KeyEvent.KEYCODE_MEDIA_STOP:
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
MediaController.getInstance().playNextMessage();
MediaController.getInstance().playNextMessage(+1, false);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
MediaController.getInstance().playPreviousMessage();
MediaController.getInstance().playNextMessage(-1, false);
break;
}
} else {
@@ -58,11 +73,11 @@ public class MusicPlayerReceiver extends BroadcastReceiver {
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_PAUSE) || intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_NEXT)) {
MediaController.getInstance().playNextMessage();
MediaController.getInstance().playNextMessage(+1, false);
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_CLOSE)) {
MediaController.getInstance().cleanupPlayer(true, true);
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_PREVIOUS)) {
MediaController.getInstance().playPreviousMessage();
MediaController.getInstance().playNextMessage(-1, false);
}
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -38,7 +53,6 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
private RemoteControlClient remoteControlClient;
private AudioManager audioManager;
private static boolean supportBigNotifications = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
private static boolean supportLockScreenControls = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
@Override
@@ -82,7 +96,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
remoteControlClient.setTransportControlFlags(RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_STOP | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
createNotification(messageObject);
@@ -93,95 +107,70 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
}
@SuppressLint("NewApi")
private void createNotification(MessageObject messageObject) {
String songName = messageObject.getMusicTitle();
String authorName = messageObject.getMusicAuthor();
private void createNotification(MessageObject messageObject)
{
AudioInfo audioInfo = MediaController.getInstance().getAudioInfo();
RemoteViews simpleContentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.player_small_notification);
RemoteViews expandedView = null;
if (supportBigNotifications) {
expandedView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.player_big_notification);
MrPoortext pt = MrMailbox.getMsg(messageObject.getId()).getMediainfo();
String authorName = pt.getText1();
String songName = pt.getText2();
if( songName == null || songName.length()==0 ) {
TLRPC.Document document = messageObject.messageOwner.media.document;
for (int i = 0; i < document.attributes.size(); i++) {
TLRPC.DocumentAttribute attr = document.attributes.get(i);
if (attr instanceof TLRPC.TL_documentAttributeAudio) {
authorName = attr.performer;
songName = attr.title;
break;
}
}
}
Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class);
intent.setAction("com.b44t.messenger.openplayer");
intent.setFlags(32768);
PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, 0);
if( songName == null || songName.length()==0 ) {
// preview of just recorded and not send voice messages
authorName = ApplicationLoader.applicationContext.getString(R.string.FromSelf);
songName = ApplicationLoader.applicationContext.getString(R.string.AttachVoiceMessage);
}
RemoteViews simpleContentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.player_small_notification);
//Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class);
//intent.setAction("com.b44t.messenger.openchat"+messageObject.getDialogId());
//intent.setFlags(32768);
//PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.player)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.notification_player)
//.setContentIntent(contentIntent)
.setContentTitle(songName).build();
notification.contentView = simpleContentView;
if (supportBigNotifications) {
notification.bigContentView = expandedView;
}
setListeners(simpleContentView);
if (supportBigNotifications) {
setListeners(expandedView);
}
Bitmap albumArt = audioInfo != null ? audioInfo.getSmallCover() : null;
if (albumArt != null) {
notification.contentView.setImageViewBitmap(R.id.player_album_art, albumArt);
if (supportBigNotifications) {
notification.bigContentView.setImageViewBitmap(R.id.player_album_art, albumArt);
}
notification.contentView.setViewVisibility(R.id.player_album_art, View.VISIBLE);
} else {
notification.contentView.setImageViewResource(R.id.player_album_art, R.drawable.nocover_small);
if (supportBigNotifications) {
notification.bigContentView.setImageViewResource(R.id.player_album_art, R.drawable.nocover_big);
}
notification.contentView.setViewVisibility(R.id.player_album_art, View.GONE);
}
if (MediaController.getInstance().isDownloadingCurrentMessage()) {
notification.contentView.setViewVisibility(R.id.player_pause, View.GONE);
notification.contentView.setViewVisibility(R.id.player_play, View.GONE);
notification.contentView.setViewVisibility(R.id.player_next, View.GONE);
notification.contentView.setViewVisibility(R.id.player_previous, View.GONE);
notification.contentView.setViewVisibility(R.id.player_progress_bar, View.VISIBLE);
if (supportBigNotifications) {
notification.bigContentView.setViewVisibility(R.id.player_pause, View.GONE);
notification.bigContentView.setViewVisibility(R.id.player_play, View.GONE);
notification.bigContentView.setViewVisibility(R.id.player_next, View.GONE);
notification.bigContentView.setViewVisibility(R.id.player_previous, View.GONE);
notification.bigContentView.setViewVisibility(R.id.player_progress_bar, View.VISIBLE);
}
} else {
notification.contentView.setViewVisibility(R.id.player_progress_bar, View.GONE);
{
notification.contentView.setViewVisibility(R.id.player_next, View.VISIBLE);
notification.contentView.setViewVisibility(R.id.player_previous, View.VISIBLE);
if (supportBigNotifications) {
notification.bigContentView.setViewVisibility(R.id.player_next, View.VISIBLE);
notification.bigContentView.setViewVisibility(R.id.player_previous, View.VISIBLE);
notification.bigContentView.setViewVisibility(R.id.player_progress_bar, View.GONE);
}
if (MediaController.getInstance().isAudioPaused()) {
notification.contentView.setViewVisibility(R.id.player_pause, View.GONE);
notification.contentView.setViewVisibility(R.id.player_play, View.VISIBLE);
if (supportBigNotifications) {
notification.bigContentView.setViewVisibility(R.id.player_pause, View.GONE);
notification.bigContentView.setViewVisibility(R.id.player_play, View.VISIBLE);
}
} else {
notification.contentView.setViewVisibility(R.id.player_pause, View.VISIBLE);
notification.contentView.setViewVisibility(R.id.player_play, View.GONE);
if (supportBigNotifications) {
notification.bigContentView.setViewVisibility(R.id.player_pause, View.VISIBLE);
notification.bigContentView.setViewVisibility(R.id.player_play, View.GONE);
}
}
}
notification.contentView.setTextViewText(R.id.player_song_name, songName);
notification.contentView.setTextViewText(R.id.player_author_name, authorName);
if (supportBigNotifications) {
notification.bigContentView.setTextViewText(R.id.player_song_name, songName);
notification.bigContentView.setTextViewText(R.id.player_author_name, authorName);
}
notification.flags |= Notification.FLAG_ONGOING_EVENT;
startForeground(5, notification);
@@ -193,7 +182,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
try {
metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover());
} catch (Throwable e) {
FileLog.e("messenger", e);
}
}
metadataEditor.apply();
@@ -203,12 +192,16 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
public void setListeners(RemoteViews view) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.player_previous, pendingIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.player_close, pendingIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.player_pause, pendingIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.player_next, pendingIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PLAY), PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.player_play, pendingIntent);
}
@@ -1,197 +0,0 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class NativeLoader {
private final static int LIB_VERSION = 1;
private final static String LIB_NAME = "messenger." + LIB_VERSION;
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
//private String crashPath = "";
private static volatile boolean nativeLoaded = false;
private static File getNativeLibraryDir(Context context) {
File f = null;
if (context != null) {
try {
f = new File((String)ApplicationInfo.class.getField("nativeLibraryDir").get(context.getApplicationInfo()));
} catch (Throwable th) {
th.printStackTrace();
}
}
if (f == null) {
f = new File(context.getApplicationInfo().dataDir, "lib");
}
if (f.isDirectory()) {
return f;
}
return null;
}
private static boolean loadFromZip(Context context, File destDir, File destLocalFile, String folder) {
try {
for (File file : destDir.listFiles()) {
file.delete();
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
ZipFile zipFile = null;
InputStream stream = null;
try {
zipFile = new ZipFile(context.getApplicationInfo().sourceDir);
ZipEntry entry = zipFile.getEntry("lib/" + folder + "/" + LIB_SO_NAME);
if (entry == null) {
throw new Exception("Unable to find file in apk:" + "lib/" + folder + "/" + LIB_NAME);
}
stream = zipFile.getInputStream(entry);
OutputStream out = new FileOutputStream(destLocalFile);
byte[] buf = new byte[4096];
int len;
while ((len = stream.read(buf)) > 0) {
Thread.yield();
out.write(buf, 0, len);
}
out.close();
destLocalFile.setReadable(true, false);
destLocalFile.setExecutable(true, false);
destLocalFile.setWritable(true);
try {
System.load(destLocalFile.getAbsolutePath());
//init(context.getCacheDir().getAbsolutePath(), BuildVars.DEBUG_VERSION);
nativeLoaded = true;
} catch (Error e) {
FileLog.e("messenger", e);
}
return true;
} catch (Exception e) {
FileLog.e("messenger", e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
if (zipFile != null) {
try {
zipFile.close();
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
}
return false;
}
public static synchronized void initNativeLibs(Context context) {
if (nativeLoaded) {
return;
}
String crashDir = context.getCacheDir().getAbsolutePath();
try {
String folder;
try {
if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) {
folder = "armeabi-v7a";
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
folder = "armeabi";
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
folder = "x86";
} else if (Build.CPU_ABI.equalsIgnoreCase("mips")) {
folder = "mips";
} else {
folder = "armeabi";
FileLog.e("messenger", "Unsupported arch: " + Build.CPU_ABI);
}
} catch (Exception e) {
FileLog.e("messenger", e);
folder = "armeabi";
}
String javaArch = System.getProperty("os.arch");
if (javaArch != null && javaArch.contains("686")) {
folder = "x86";
}
File destFile = getNativeLibraryDir(context);
if (destFile != null) {
destFile = new File(destFile, LIB_SO_NAME);
if (destFile.exists()) {
FileLog.d("messenger", "load normal lib");
try {
System.loadLibrary(LIB_NAME);
//init(crashDir, BuildVars.DEBUG_VERSION);
nativeLoaded = true;
return;
} catch (Error e) {
FileLog.e("messenger", e);
}
}
}
File destDir = new File(context.getFilesDir(), "lib");
destDir.mkdirs();
File destLocalFile = new File(destDir, LOCALE_LIB_SO_NAME);
if (destLocalFile.exists()) {
try {
FileLog.d("messenger", "Load local lib");
System.load(destLocalFile.getAbsolutePath());
//init(crashDir, BuildVars.DEBUG_VERSION);
nativeLoaded = true;
return;
} catch (Error e) {
FileLog.e("messenger", e);
}
destLocalFile.delete();
}
FileLog.e("messenger", "Library not found, arch = " + folder);
if (loadFromZip(context, destDir, destLocalFile, folder)) {
return;
}
} catch (Throwable e) {
e.printStackTrace();
}
try {
System.loadLibrary(LIB_NAME);
//init(crashDir, BuildVars.DEBUG_VERSION);
nativeLoaded = true;
} catch (Error e) {
FileLog.e("messenger", e);
}
}
//private static native void init(String path, boolean enableGoglBreakpad); // not needed
//public static native void crash();
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -16,72 +31,35 @@ public class NotificationCenter {
private static int totalEvents = 1;
public static final int connectionStateChanged = totalEvents++;
public static final int configureEnded = totalEvents++;
public static final int configureProgress = totalEvents++;
public static final int didReceivedNewMessages = totalEvents++;
public static final int updateInterfaces = totalEvents++;
public static final int dialogsNeedReload = totalEvents++;
public static final int closeChats = totalEvents++;
public static final int messagesDeleted = totalEvents++;
public static final int messagesSentOrRead = totalEvents++;
public static final int messageReceivedByAck = totalEvents++;
public static final int messageReceivedByServer = totalEvents++;
public static final int messageSendError = totalEvents++;
public static final int contactsDidLoaded = totalEvents++;
public static final int chatDidCreated = totalEvents++;
public static final int chatDidFailCreate = totalEvents++;
public static final int mediaDidLoaded = totalEvents++;
public static final int mediaCountDidLoaded = totalEvents++;
public static final int dialogPhotosLoaded = totalEvents++;
public static final int removeAllMessagesFromDialog = totalEvents++;
public static final int notificationsSettingsUpdated = totalEvents++;
public static final int pushMessagesUpdated = totalEvents++;
public static final int blockedUsersDidLoaded = totalEvents++;
public static final int openedChatChanged = totalEvents++;
public static final int stopEncodingService = totalEvents++;
public static final int didCreatedNewDeleteTask = totalEvents++;
public static final int mainUserInfoChanged = totalEvents++;
public static final int updateMessageMedia = totalEvents++;
public static final int recentImagesDidLoaded = totalEvents++;
public static final int replaceMessagesObjects = totalEvents++;
public static final int waveformCalculated = totalEvents++;
public static final int didSetPasscode = totalEvents++;
//public static final int screenStateChanged = totalEvents++; -- currently not used, but this may get handy
public static final int didLoadedReplyMessages = totalEvents++;
public static final int didReceivedWebpages = totalEvents++;
public static final int didReceivedWebpagesInUpdates = totalEvents++;
public static final int stickersDidLoaded = totalEvents++;
public static final int didReplacedPhotoInMemCache = totalEvents++;
public static final int messagesReadContent = totalEvents++;
public static final int userInfoDidLoaded = totalEvents++;
public static final int chatSearchResultsAvailable = totalEvents++;
public static final int musicDidLoaded = totalEvents++;
public static final int didUpdatedMessagesViews = totalEvents++;
public static final int needReloadRecentDialogsSearch = totalEvents++;
public static final int locationPermissionGranted = totalEvents++;
public static final int peerSettingsDidLoaded = totalEvents++;
public static final int wasUnableToFindCurrentLocation = totalEvents++;
public static final int reloadHints = totalEvents++;
public static final int reloadInlineHints = totalEvents++;
public static final int newDraftReceived = totalEvents++;
public static final int httpFileDidLoaded = totalEvents++;
public static final int httpFileDidFailedLoad = totalEvents++;
public static final int messageThumbGenerated = totalEvents++;
public static final int wallpapersDidLoaded = totalEvents++;
public static final int closeOtherAppActivities = totalEvents++;
public static final int didUpdatedConnectionState = totalEvents++;
public static final int didReceiveSmsCode = totalEvents++;
public static final int didReceiveCall = totalEvents++;
public static final int emojiDidLoaded = totalEvents++;
public static final int appDidLogout = totalEvents++;
public static final int FileDidUpload = totalEvents++;
public static final int FileDidFailUpload = totalEvents++;
public static final int FileUploadProgressChanged = totalEvents++;
public static final int FileLoadProgressChanged = totalEvents++;
public static final int FileDidLoaded = totalEvents++;
public static final int FileDidFailedLoad = totalEvents++;
public static final int FilePreparingStarted = totalEvents++;
public static final int FileNewChunkAvailable = totalEvents++;
public static final int FilePreparingFailed = totalEvents++;
@@ -93,7 +71,6 @@ public class NotificationCenter {
public static final int recordStarted = totalEvents++;
public static final int recordStartError = totalEvents++;
public static final int recordStopped = totalEvents++;
public static final int screenshotTook = totalEvents++;
public static final int albumsDidLoaded = totalEvents++;
public static final int audioDidSent = totalEvents++;
public static final int audioDidStarted = totalEvents++;
@@ -173,17 +150,18 @@ public class NotificationCenter {
}
public void postNotificationNameInternal(int id, boolean allowDuringAnimation, Object... args) {
if (BuildVars.DEBUG_VERSION) {
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
throw new RuntimeException("postNotificationName allowed only from MAIN thread");
}
}
}*/
if (!allowDuringAnimation && animationInProgress) {
DelayedPost delayedPost = new DelayedPost(id, args);
delayedPosts.add(delayedPost);
if (BuildVars.DEBUG_VERSION) {
FileLog.e("messenger", "delay post notification " + id + " with args count = " + args.length);
}
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
Log.i("DeltaChat", "delay post notification " + id + " with args count = " + args.length);
}*/
return;
}
broadcasting++;
@@ -220,11 +198,11 @@ public class NotificationCenter {
}
public void addObserver(Object observer, int id) {
if (BuildVars.DEBUG_VERSION) {
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
throw new RuntimeException("addObserver allowed only from MAIN thread");
}
}
}*/
if (broadcasting != 0) {
ArrayList<Object> arrayList = addAfterBroadcast.get(id);
if (arrayList == null) {
@@ -245,11 +223,11 @@ public class NotificationCenter {
}
public void removeObserver(Object observer, int id) {
if (BuildVars.DEBUG_VERSION) {
/*if (BuildConfig.BUILD_TYPE.equals("debug")) {
if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) {
throw new RuntimeException("removeObserver allowed only from MAIN thread");
}
}
}*/
if (broadcasting != 0) {
ArrayList<Object> arrayList = removeAfterBroadcast.get(id);
if (arrayList == null) {
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -18,6 +33,6 @@ public class NotificationDismissReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
preferences.edit().putInt("dismissDate", intent.getIntExtra("messageDate", 0)).commit();
preferences.edit().putInt("dismissDate", intent.getIntExtra("messageDate", 0)).apply();
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
File diff suppressed because it is too large Load Diff
@@ -1,43 +0,0 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
public class NotificationsService extends Service {
@Override
public void onCreate() {
FileLog.e("messenger", "service started");
ApplicationLoader.postInitApplication();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
FileLog.e("messenger", "service destroyed");
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE);
if (preferences.getBoolean("pushService", true)) {
Intent intent = new Intent("com.b44t.start");
sendBroadcast(intent);
}
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -1,28 +1,42 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
FileLog.e("messenger", "screen off");
ConnectionsManager.getInstance().setAppPaused(true, true);
MrMailbox.log_i("DeltaChat", "*** Screen off");
ApplicationLoader.isScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
FileLog.e("messenger", "screen on");
ConnectionsManager.getInstance().setAppPaused(false, true);
MrMailbox.log_i("DeltaChat", "*** Screen on");
ApplicationLoader.isScreenOn = true;
}
//NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenStateChanged);
File diff suppressed because it is too large Load Diff
@@ -1,29 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class ShareBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String url = intent.getDataString();
if (url != null) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
Intent chooserIntent = Intent.createChooser(shareIntent, LocaleController.getString("ShareLink", R.string.ShareLink));
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(chooserIntent);
}
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -17,19 +32,15 @@ public class TLRPC {
public static final int MESSAGE_FLAG_REPLY = 0x00000008;
public static final int MESSAGE_FLAG_HAS_FROM_ID = 0x00000100;
public static final int MESSAGE_FLAG_HAS_MEDIA = 0x00000200;
public static final int MESSAGE_FLAG_EDITED = 0x00008000;
public static class DraftMessage extends TLObject {
public int flags;
public boolean no_webpage;
public int reply_to_msg_id;
public String message;
public ArrayList<MessageEntity> entities = new ArrayList<>();
public int date;
}
public static class ChatPhoto extends TLObject {
public FileLocation photo_small;
public FileLocation photo_big;
}
@@ -39,7 +50,6 @@ public class TLRPC {
public int duration;
public String alt;
public InputStickerSet stickerset;
public int flags;
public boolean voice;
public String title;
public String performer;
@@ -65,177 +75,35 @@ public class TLRPC {
public static class TL_documentAttributeFilename extends DocumentAttribute {
}
public static class messages_Messages extends TLObject {
public ArrayList<Message> messages = new ArrayList<>();
public ArrayList<Chat> chats = new ArrayList<>();
public ArrayList<User> users = new ArrayList<>();
public int flags;
public int pts;
public int count;
}
public static class TL_messages_messages extends messages_Messages {
}
public static class Peer extends TLObject {
public final int channel_id = 0;
public int user_id;
public int chat_id;
public final int chat_id = 0;
}
public static class TL_peerUser extends Peer {
}
public static class TL_peerChat extends Peer {
}
public static class GeoPoint extends TLObject {
public double _long;
public double lat;
}
public static class TL_geoPoint extends GeoPoint {
}
public static class TL_messageMediaEmpty extends MessageMedia {
}
public static class TL_messageMediaVenue extends MessageMedia {
}
public static class TL_messageMediaDocument extends MessageMedia {
}
public static class TL_messageMediaContact extends MessageMedia {
}
public static class TL_messageMediaPhoto extends MessageMedia {
}
public static class TL_messageMediaGeo extends MessageMedia {
}
public static class TL_messageMediaWebPage extends MessageMedia {
}
public static class BotInlineResult extends TLObject {
public int flags;
public String id;
public String type;
public String title;
public String description;
public String url;
public String thumb_url;
public String content_url;
public String content_type;
public int w;
public int h;
public int duration;
public Photo photo;
public Document document;
}
public static class PeerNotifySettings extends TLObject {
public int flags;
public boolean silent;
public int mute_until;
public String sound;
}
public static class TL_peerNotifySettings extends PeerNotifySettings {
}
public static class TL_messages_stickerSet extends TLObject {
public StickerSet set;
public ArrayList<TL_stickerPack> packs = new ArrayList<>();
public ArrayList<Document> documents = new ArrayList<>();
}
public static class InputGeoPoint extends TLObject {
public double lat;
public double _long;
}
public static class TL_inputGeoPoint extends InputGeoPoint {
}
public static class Audio extends TLObject {
public long id;
public int date;
public int duration;
public String mime_type;
public int size;
public int dc_id;
public int user_id;
public byte[] key;
public byte[] iv;
}
public static class ChatFull extends TLObject {
public int flags;
public int id;
public String about;
public int pinned_msg_id;
public ChatParticipants participants;
}
public static class TL_topPeerCategoryPeers extends TLObject {
public TopPeerCategory category;
public int count;
}
public static class InputUser extends TLObject {
public int user_id;
public long access_hash;
}
public static class TL_inputUserEmpty extends InputUser {
}
public static class TL_inputUserSelf extends InputUser {
}
public static class TL_inputUser extends InputUser {
}
public static class WebPage extends TLObject {
public int flags;
public long id;
public String url;
public String display_url;
public String type;
public String site_name;
public String title;
public String description;
public Photo photo;
public String embed_url;
public int embed_width;
public int embed_height;
public int duration;
public String author;
public int date;
public Document document;
}
public static class TL_webPageEmpty extends WebPage {
}
public static class TL_webPage extends WebPage {
}
public static class InputFileLocation extends TLObject {
public long id;
public long access_hash;
public long volume_id;
public int local_id;
public long secret;
}
public static class TL_inputDocumentFileLocation extends InputFileLocation {
}
public static class TL_inputFileLocation extends InputFileLocation {
}
public static class User extends TLObject {
@@ -243,58 +111,10 @@ public class TLRPC {
public String first_name;
public String last_name;
public String username;
public final long access_hash = 0;
public String phone;
public UserProfilePhoto photo;
public UserStatus status;
public int flags;
public boolean self;
public boolean contact;
public final boolean mutual_contact = false;
public final boolean deleted = false;
public final boolean bot = false;
public boolean verified;
public boolean min;
}
public static class TL_userContact_old2 extends User {
}
public static class MessageAction extends TLObject {
public String title;
public String address;
public ArrayList<Integer> users = new ArrayList<>();
public final int channel_id = 0;
public Photo photo;
public int chat_id;
public int user_id;
public UserProfilePhoto newUserPhoto;
}
public static class TL_messageActionChatCreate extends MessageAction {
}
public static class TL_messageActionChatEditPhoto extends MessageAction {
}
public static class TL_messageActionChatAddUser extends MessageAction {
}
public static class TL_messageActionChatDeleteUser extends MessageAction {
}
public static class TL_messageActionUserUpdatedPhoto extends MessageAction {
}
public static class TL_messageActionChatDeletePhoto extends MessageAction {
}
public static class TL_messageActionChatEditTitle extends MessageAction {
}
public static class TL_messageActionEmpty extends MessageAction {
}
public static class Video extends TLObject {
public long id;
public int user_id;
@@ -302,24 +122,10 @@ public class TLRPC {
public int duration;
public int size;
public PhotoSize thumb;
public int dc_id;
public int w;
public int h;
public String mime_type;
public String caption;
public byte[] key;
public byte[] iv;
}
public static class TopPeerCategory extends TLObject {
}
public static class InputDocument extends TLObject {
public long id;
public long access_hash;
}
public static class TL_inputDocument extends InputDocument {
}
public static class Document extends TLObject {
@@ -342,136 +148,21 @@ public class TLRPC {
public static class TL_document extends Document {
}
public static class InputMedia extends TLObject {
public InputFile file;
public InputFile thumb;
public String mime_type;
public ArrayList<DocumentAttribute> attributes = new ArrayList<>();
public String caption;
public InputGeoPoint geo_point;
public String title;
public String address;
public String provider;
public String venue_id;
public String phone_number;
public String first_name;
public String last_name;
public String url;
public String q;
}
public static class TL_inputMediaContact extends InputMedia {
}
public static class TL_inputMediaUploadedThumbDocument extends InputMedia {
}
public static class TL_inputMediaDocument extends InputMedia {
public InputDocument id;
}
public static class TL_inputMediaGifExternal extends InputMedia {
}
public static class TL_inputMediaGeoPoint extends InputMedia {
}
public static class TL_inputMediaUploadedPhoto extends InputMedia {
}
public static class TL_inputMediaVenue extends InputMedia {
}
public static class TL_inputMediaUploadedDocument extends InputMedia {
}
public static class TL_inputMediaPhoto extends InputMedia {
public InputPhoto id;
}
public static class InputStickerSet extends TLObject {
public long id;
public long access_hash;
public String short_name;
}
public static class TL_inputStickerSetEmpty extends InputStickerSet {
}
public static class TL_inputStickerSetID extends InputStickerSet {
}
public static class TL_inputStickerSetShortName extends InputStickerSet {
}
public static class UserStatus extends TLObject {
public int expires;
}
public static class TL_userStatusLastWeek extends UserStatus {
}
public static class TL_userStatusLastMonth extends UserStatus {
}
public static class TL_userStatusRecently extends UserStatus {
}
public static class InputEncryptedFile extends TLObject {
public long id;
public int parts;
}
public static class UserProfilePhoto extends TLObject {
public FileLocation photo_small;
public FileLocation photo_big;
}
public static class MessageEntity extends TLObject {
public int offset;
public int length;
public String url;
public String language;
}
public static class TL_messageEntityTextUrl extends MessageEntity {
}
public static class TL_messageEntityEmail extends MessageEntity {
}
public static class TL_messageEntityPre extends MessageEntity {
}
public static class TL_messageEntityUrl extends MessageEntity {
}
public static class TL_messageEntityItalic extends MessageEntity {
}
public static class TL_messageEntityMention extends MessageEntity {
}
public static class TL_messageEntityMentionName extends MessageEntity {
public int user_id;
}
public static class TL_inputMessageEntityMentionName extends MessageEntity {
public InputUser user_id;
}
public static class TL_messageEntityBold extends MessageEntity {
}
public static class TL_messageEntityHashtag extends MessageEntity {
}
public static class TL_messageEntityCode extends MessageEntity {
}
public static class Photo extends TLObject {
public long id;
public long access_hash;
public int user_id;
public int date;
public String caption;
@@ -484,48 +175,22 @@ public class TLRPC {
public static class TL_photoEmpty extends Photo {
}
public static class TL_contact extends TLObject {
public int user_id;
public boolean mutual;
}
public static class ChatParticipants extends TLObject {
public int flags;
public int chat_id;
public ArrayList<ChatParticipant> participants = new ArrayList<>();
public int version;
}
public static class ChatParticipant extends TLObject {
public int user_id;
public int date;
}
public static class Chat extends TLObject {
public int flags;
public boolean creator;
public boolean kicked;
public boolean deactivated;
public int id;
public String title;
public final ChatPhoto photo = null;
public int date;
public int version;
public boolean editor;
public final boolean broadcast = false;
public boolean verified;
public final boolean megagroup = false;
public boolean left;
public final int version = 0;
public final boolean editor = false;
public String username;
public boolean restricted;
public boolean signatures;
public boolean min;
public String address;
public final boolean signatures = false;
public final boolean min = false;
public final String address = null;
}
public static class StickerSet extends TLObject {
public long id;
public long access_hash;
public String title;
public int flags;
public boolean installed;
@@ -535,33 +200,8 @@ public class TLRPC {
public int hash;
}
public static class MessagesFilter extends TLObject {
}
public static class TL_inputMessagesFilterDocument extends MessagesFilter {
}
public static class TL_inputMessagesFilterMusic extends MessagesFilter {
}
public static class TL_inputMessagesFilterUrl extends MessagesFilter {
}
public static class TL_inputMessagesFilterVoice extends MessagesFilter {
}
public static class TL_inputMessagesFilterEmpty extends MessagesFilter {
}
public static class TL_inputMessagesFilterPhotoVideo extends MessagesFilter {
}
public static class TL_messageFwdHeader extends TLObject {
public int flags;
public int from_id;
public int date;
public int channel_id;
public int channel_post;
public String m_name;
}
public static class FileLocation extends TLObject {
@@ -580,7 +220,7 @@ public class TLRPC {
}
public static class PhotoSize extends TLObject {
public String type;
public String type; // s, m, x, y, w for small, medium, ... widest
public FileLocation location;
public int w;
public int h;
@@ -618,68 +258,15 @@ public class TLRPC {
public static class TL_wallPaperSolid extends WallPaper {
}
public static class TL_stickerPack extends TLObject {
public ArrayList<Long> documents = new ArrayList<>();
}
public static class InputPhoto extends TLObject {
public long id;
public long access_hash;
}
public static class TL_inputPhoto extends InputPhoto {
}
public static class InputPeer extends TLObject {
public int user_id;
public long access_hash;
public int chat_id;
public int channel_id;
}
public static class TL_inputPeerUser extends InputPeer {
}
public static class TL_inputPeerEmpty extends InputPeer {
}
public static class TL_topPeer extends TLObject {
public Peer peer;
}
public static class TL_messages_search extends TLObject {
public int flags;
public InputPeer peer;
public String q;
public MessagesFilter filter;
public int offset;
public int max_id;
public int limit;
}
public static class TL_messages_searchGlobal extends TLObject {
public String q;
public int offset_date;
public InputPeer offset_peer;
public int offset_id;
public int limit;
}
public static class MessageMedia extends TLObject {
public byte[] bytes;
public Photo photo;
public GeoPoint geo;
public String title;
public String address;
public String provider;
public String venue_id;
public Document document;
public String caption;
public String phone_number;
public String first_name;
public String last_name;
public int user_id;
public WebPage webpage;
}
public static class Message extends TLObject {
@@ -687,60 +274,35 @@ public class TLRPC {
public int from_id;
public Peer to_id;
public int date;
public MessageAction action;
public int reply_to_msg_id;
public long reply_to_random_id;
public final int reply_to_msg_id = 0;
public String message;
public MessageMedia media;
public int flags;
public boolean mentioned;
public boolean media_unread;
public boolean out;
public boolean unread;
public ArrayList<MessageEntity> entities = new ArrayList<>();
public String via_bot_name;
public int views;
public int edit_date;
public boolean silent;
public boolean post;
public final int views = 0;
public final boolean silent = false;
public final boolean post = false;// ? true=avatar wird in gruppen nicht angezeigt, wird aber in isFromUser() auch überprüft...
public TL_messageFwdHeader fwd_from;
public int via_bot_id;
public int send_state = 0; //custom
public String attachPath = ""; //custom
public HashMap<String, String> params; //custom
public long random_id; //custom
public long dialog_id; //custom
public int ttl; //custom
public int destroyTime; //custom
public int layer; //custom
public TLRPC.Message replyMessage; //custom
public final int layer = 0; //custom
public boolean created_by_mr;
}
public static class TL_messageEmpty extends Message {
}
public static class TL_message extends Message {
}
public static class TL_messageService extends Message {
}
public static class TL_dialog extends TLObject {
final public int flags = 0;
public Peer peer;
public int top_message;
public int unread_count;
public PeerNotifySettings notify_settings;
public int pts;
public final int top_message = 0;
public final int unread_count = 0;
public final int pts = 0;
public DraftMessage draft;
public int last_message_date; //custom
public long id; //custom
}
public static class TL_chatEmpty extends Chat {
}
public static class Vector extends TLObject {
public ArrayList<Object> objects = new ArrayList<>();
}
}
@@ -1,172 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
// ChooserTargetService, see https://developer.android.com/reference/android/service/chooser/ChooserTargetService.html
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
import com.b44t.ui.LaunchActivity;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
@TargetApi(Build.VERSION_CODES.M)
public class TgChooserTargetService extends ChooserTargetService {
@Override
public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
final List<ChooserTarget> targets = new ArrayList<>();
if (!UserConfig.isClientActivated()) {
return targets;
}
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
if (!preferences.getBoolean("direct_share", true)) {
return targets;
}
ImageLoader imageLoader = ImageLoader.getInstance();
final Semaphore semaphore = new Semaphore(0);
final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName());
/*
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
@Override
public void run() {
ArrayList<Integer> dialogs = new ArrayList<>();
ArrayList<TLRPC.Chat> chats = new ArrayList<>();
ArrayList<TLRPC.User> users = new ArrayList<>();
try {
ArrayList<Integer> usersToLoad = new ArrayList<>();
usersToLoad.add(UserConfig.getClientUserId());
ArrayList<Integer> chatsToLoad = new ArrayList<>();
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs ORDER BY date DESC LIMIT %d,%d", 0, 30));
while (cursor.next()) {
long id = cursor.longValue(0);
int lower_id = (int) id;
int high_id = (int) (id >> 32);
if (lower_id != 0) {
if (high_id == 1) {
continue;
} else {
if (lower_id > 0) {
if (!usersToLoad.contains(lower_id)) {
usersToLoad.add(lower_id);
}
} else {
if (!chatsToLoad.contains(-lower_id)) {
chatsToLoad.add(-lower_id);
}
}
}
} else {
continue;
}
dialogs.add(lower_id);
if (dialogs.size() == 8) {
break;
}
}
cursor.dispose();
if (!chatsToLoad.isEmpty()) {
//MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats);
}
if (!usersToLoad.isEmpty()) {
//MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
for (int a = 0; a < dialogs.size(); a++) {
Bundle extras = new Bundle();
Icon icon = null;
String name = null;
int id = dialogs.get(a);
if (id > 0) {
for (int b = 0; b < users.size(); b++) {
TLRPC.User user = users.get(b);
if (user.id == id) {
if (!user.bot) {
extras.putLong("dialogId", (long) id);
if (user.photo != null && user.photo.photo_small != null) {
icon = createRoundBitmap(FileLoader.getPathToAttach(user.photo.photo_small, true));
}
name = ContactsController.formatName(user.first_name, user.last_name);
}
break;
}
}
} else {
for (int b = 0; b < chats.size(); b++) {
TLRPC.Chat chat = chats.get(b);
if (chat.id == -id) {
if (!ChatObject.isNotInChat(chat) && (!ChatObject.isChannel(chat) || chat.megagroup)) {
extras.putLong("dialogId", (long) id);
if (chat.photo != null && chat.photo.photo_small != null) {
icon = createRoundBitmap(FileLoader.getPathToAttach(chat.photo.photo_small, true));
}
name = chat.title;
}
break;
}
}
}
if (name != null) {
if (icon == null) {
icon = Icon.createWithResource(ApplicationLoader.applicationContext, R.drawable.logo_avatar);
}
targets.add(new ChooserTarget(name, icon, 1.0f, componentName, extras));
}
}
semaphore.release();
}
});
*/
try {
semaphore.acquire();
} catch (Exception e) {
FileLog.e("messenger", e);
}
return targets;
}
/*
private Icon createRoundBitmap(File path) {
try {
Bitmap bitmap = BitmapFactory.decodeFile(path.toString());
if (bitmap != null) {
Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
result.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(result);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
if (roundPaint == null) {
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapRect = new RectF();
}
roundPaint.setShader(shader);
bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawRoundRect(bitmapRect, bitmap.getWidth(), bitmap.getHeight(), roundPaint);
return Icon.createWithBitmap(result);
}
} catch (Throwable e) {
FileLog.e("messenger", e);
}
return null;
}
*/
}
@@ -0,0 +1,72 @@
/*******************************************************************************
*
* Messenger Android Frontend
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
public class TimerReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// acquire for 3 seconds, this should wake up the threads,
// _if_ there is more to do, the backend acquires an additional wakelock using MR_EVENT_WAKE_LOCK
ApplicationLoader.wakeupWakeLock.acquire(3*1000); // do this first!
MrMailbox.log_i("DeltaChat", "*** TimerReceiver.onReceive()");
// we assume, the IMAP thread is alive. I cannot imagine, the thread was killed with the App being running.
// (if the whole App was killed, the IMAP thread is already started by MrMailbox.connect() if we're here)
// (the thread itself will reconnect to the IMAP server as needed)
// however, it seems as if the threads sleep longer than ususal, check this by calling heartbeat() manually
MrMailbox.heartbeat();
// create the next alarm in about a minute
scheduleNextAlarm();
}
public static void scheduleNextAlarm()
{
try {
Intent intent = new Intent(ApplicationLoader.applicationContext, TimerReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, intent, 0);
long triggerAtMillis = System.currentTimeMillis() + 60 * 1000;
AlarmManager alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Activity.ALARM_SERVICE);
if( Build.VERSION.SDK_INT >= 23 ) {
// a simple AlarmManager.set() is no longer send in the new DOZE mode
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, alarmIntent);
}
else {
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, alarmIntent);
}
}
catch(Exception e) { Log.e("DeltaChat", "Cannot create alarm.", e); }
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -16,16 +31,8 @@ import java.io.File;
public class UserConfig {
private static TLRPC.User currentUser;
public static boolean registeredForPush;
public static String pushString = "";
public static int lastSendMessageId = -210000;
public static int lastLocalId = -210000;
public static int lastBroadcastId = -1;
public static String contactsHash = "";
public static boolean blockedUsersLoaded;
private final static Object sync = new Object();
public static boolean saveIncomingPhotos;
public static String passcodeHash = "";
public static byte[] passcodeSalt = new byte[0];
public static boolean appLocked;
@@ -34,228 +41,38 @@ public class UserConfig {
public static int lastPauseTime;
public static boolean isWaitingForPasscodeEnter;
public static boolean useFingerprint = true;
public static String lastUpdateVersion;
public static int lastContactsSyncTime;
public static int lastHintsSyncTime;
public static boolean draftsLoaded;
public static int migrateOffsetId = -1;
public static int migrateOffsetDate = -1;
public static int migrateOffsetUserId = -1;
public static int migrateOffsetChatId = -1;
public static int migrateOffsetChannelId = -1;
public static long migrateOffsetAccess = -1;
public static int getNewMessageId() {
int id;
synchronized (sync) {
id = lastSendMessageId;
lastSendMessageId--;
}
return id;
}
public static void saveConfig(boolean withFile) {
saveConfig(withFile, null);
}
public static void saveConfig(boolean withFile, File oldFile) {
public static void saveConfig() {
synchronized (sync) {
try {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("userconfing", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("registeredForPush", registeredForPush);
editor.putString("pushString2", pushString);
editor.putInt("lastSendMessageId", lastSendMessageId);
editor.putInt("lastLocalId", lastLocalId);
editor.putString("contactsHash", contactsHash);
editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos);
editor.putInt("lastBroadcastId", lastBroadcastId);
editor.putBoolean("blockedUsersLoaded", blockedUsersLoaded);
editor.putString("passcodeHash1", passcodeHash);
editor.putString("passcodeSalt", passcodeSalt.length > 0 ? Base64.encodeToString(passcodeSalt, Base64.DEFAULT) : "");
editor.putBoolean("appLocked", appLocked);
editor.putInt("passcodeType", passcodeType);
editor.putInt("autoLockIn", autoLockIn);
editor.putInt("lastPauseTime", lastPauseTime);
editor.putString("lastUpdateVersion2", lastUpdateVersion);
editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
editor.putBoolean("useFingerprint", useFingerprint);
editor.putInt("lastHintsSyncTime", lastHintsSyncTime);
editor.putBoolean("draftsLoaded", draftsLoaded);
editor.putInt("migrateOffsetId", migrateOffsetId);
if (migrateOffsetId != -1) {
editor.putInt("migrateOffsetDate", migrateOffsetDate);
editor.putInt("migrateOffsetUserId", migrateOffsetUserId);
editor.putInt("migrateOffsetChatId", migrateOffsetChatId);
editor.putInt("migrateOffsetChannelId", migrateOffsetChannelId);
editor.putLong("migrateOffsetAccess", migrateOffsetAccess);
}
/*
if (currentUser != null) {
if (withFile) {
SerializedData data = new SerializedData();
currentUser.serializeToStream(data);
String userString = Base64.encodeToString(data.toByteArray(), Base64.DEFAULT);
editor.putString("user", userString);
data.cleanup();
}
} else {
editor.remove("user");
}
*/
editor.commit();
if (oldFile != null) {
oldFile.delete();
}
editor.apply();
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
}
public static boolean isClientActivated() {
return true; // EDIT BY MR -- for "real" checking, call MrMailbox.MrMailboxIsConfigured()
/* EDIT BY MR
synchronized (sync) {
return currentUser != null;
}
*/
}
public static int getClientUserId() {
return 1; // we are user #1 by definition
/* EDIT BY MR
synchronized (sync) {
return currentUser != null ? currentUser.id : 0;
}
*/
}
public static TLRPC.User getCurrentUser() {
synchronized (sync) {
if( currentUser==null ) {
currentUser = MrContact.contactId2user(1);
}
return currentUser;
}
}
public static void setCurrentUser(TLRPC.User user) {
synchronized (sync) {
currentUser = MrContact.contactId2user(1); // EDIT BY MR - force the current user to be user #1, normally this function should not be called at all
}
}
public static void loadConfig() {
synchronized (sync) {
/*
final File configFile = new File(ApplicationLoader.getFilesDirFixed(), "user.dat");
if (configFile.exists()) {
try {
SerializedData data = new SerializedData(configFile);
int ver = data.readInt32(false);
if (ver == 1) {
int constructor = data.readInt32(false);
currentUser = TLRPC.User.TLdeserialize(data, constructor, false);
MessagesStorage.lastDateValue = data.readInt32(false);
MessagesStorage.lastPtsValue = data.readInt32(false);
MessagesStorage.lastSeqValue = data.readInt32(false);
registeredForPush = data.readBool(false);
pushString = data.readString(false);
lastSendMessageId = data.readInt32(false);
lastLocalId = data.readInt32(false);
contactsHash = data.readString(false);
data.readString(false);
saveIncomingPhotos = data.readBool(false);
//MessagesStorage.lastQtsValue = data.readInt32(false);
//MessagesStorage.lastSecretVersion = data.readInt32(false);
int val = data.readInt32(false);
//if (val == 1) {
// MessagesStorage.secretPBytes = data.readByteArray(false);
//}
//MessagesStorage.secretG = data.readInt32(false);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
saveConfig(true, configFile);
}
});
} else if (ver == 2) {
int constructor = data.readInt32(false);
currentUser = TLRPC.User.TLdeserialize(data, constructor, false);
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("userconfing", Context.MODE_PRIVATE);
registeredForPush = preferences.getBoolean("registeredForPush", false);
pushString = preferences.getString("pushString2", "");
lastSendMessageId = preferences.getInt("lastSendMessageId", -210000);
lastLocalId = preferences.getInt("lastLocalId", -210000);
contactsHash = preferences.getString("contactsHash", "");
saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false);
}
if (lastLocalId > -210000) {
lastLocalId = -210000;
}
if (lastSendMessageId > -210000) {
lastSendMessageId = -210000;
}
data.cleanup();
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
saveConfig(true, configFile);
}
});
} catch (Exception e) {
FileLog.e("messenger", e);
}
} else
*/
{
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("userconfing", Context.MODE_PRIVATE);
registeredForPush = preferences.getBoolean("registeredForPush", false);
pushString = preferences.getString("pushString2", "");
lastSendMessageId = preferences.getInt("lastSendMessageId", -210000);
lastLocalId = preferences.getInt("lastLocalId", -210000);
contactsHash = preferences.getString("contactsHash", "");
saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false);
lastBroadcastId = preferences.getInt("lastBroadcastId", -1);
blockedUsersLoaded = preferences.getBoolean("blockedUsersLoaded", false);
passcodeHash = preferences.getString("passcodeHash1", "");
appLocked = preferences.getBoolean("appLocked", false);
passcodeType = preferences.getInt("passcodeType", 0);
autoLockIn = preferences.getInt("autoLockIn", 60 * 60);
lastPauseTime = preferences.getInt("lastPauseTime", 0);
useFingerprint = preferences.getBoolean("useFingerprint", true);
lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5");
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
lastHintsSyncTime = preferences.getInt("lastHintsSyncTime", (int) (System.currentTimeMillis() / 1000) - 25 * 60 * 60);
draftsLoaded = preferences.getBoolean("draftsLoaded", false);
migrateOffsetId = preferences.getInt("migrateOffsetId", 0);
if (migrateOffsetId != -1) {
migrateOffsetDate = preferences.getInt("migrateOffsetDate", 0);
migrateOffsetUserId = preferences.getInt("migrateOffsetUserId", 0);
migrateOffsetChatId = preferences.getInt("migrateOffsetChatId", 0);
migrateOffsetChannelId = preferences.getInt("migrateOffsetChannelId", 0);
migrateOffsetAccess = preferences.getLong("migrateOffsetAccess", 0);
}
/*
String user = preferences.getString("user", null);
if (user != null) {
byte[] userBytes = Base64.decode(user, Base64.DEFAULT);
if (userBytes != null) {
SerializedData data = new SerializedData(userBytes);
currentUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false);
data.cleanup();
}
}
*/
setCurrentUser(null);
String passcodeSaltString = preferences.getString("passcodeSalt", "");
if (passcodeSaltString.length() > 0) {
@@ -263,7 +80,6 @@ public class UserConfig {
} else {
passcodeSalt = new byte[0];
}
}
}
}
@@ -280,9 +96,9 @@ public class UserConfig {
System.arraycopy(passcodeBytes, 0, bytes, 16, passcodeBytes.length);
System.arraycopy(passcodeSalt, 0, bytes, passcodeBytes.length + 16, 16);
passcodeHash = Utilities.bytesToHex(Utilities.computeSHA256(bytes, 0, bytes.length));
saveConfig(false);
saveConfig();
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
return result;
@@ -296,7 +112,7 @@ public class UserConfig {
String hash = Utilities.bytesToHex(Utilities.computeSHA256(bytes, 0, bytes.length));
return passcodeHash.equals(hash);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
return false;
@@ -1,24 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
public class UserObject {
public static boolean isDeleted(TLRPC.User user) {
return user == null || user.deleted;
}
public static boolean isUserSelf(TLRPC.User user) {
return user.self;
}
public static String getUserName(TLRPC.User user) {
return "ErrName"; // use MrContact.getName() instead
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -41,7 +56,7 @@ public class Utilities {
sUrandomIn.close();
random.setSeed(buffer);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
@@ -52,15 +67,8 @@ public class Utilities {
public native static void calcCDT(ByteBuffer hsvBuffer, int width, int height, ByteBuffer buffer);
public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin);
public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
//private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length);
public native static String readlink(String path);
/*
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length);
}
*/
public static Integer parseInt(String value) {
if (value == null) {
return 0;
@@ -73,7 +81,7 @@ public class Utilities {
val = Integer.parseInt(num);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return val;
}
@@ -90,19 +98,11 @@ public class Utilities {
val = Long.parseLong(num);
}
} catch (Exception e) {
FileLog.e("messenger", e);
}
return val;
}
public static String parseIntToString(String value) {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {
return matcher.group(0);
}
return null;
}
public static String bytesToHex(byte[] bytes) {
if (bytes == null) {
return "";
@@ -117,138 +117,17 @@ public class Utilities {
return new String(hexChars);
}
public static byte[] hexToBytes(String hex) {
if (hex == null) {
return null;
}
int len = hex.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
}
return data;
}
public static boolean isGoodPrime(byte[] prime, int g) {
if (!(g >= 2 && g <= 7)) {
return false;
}
if (prime.length != 256 || prime[0] >= 0) {
return false;
}
BigInteger dhBI = new BigInteger(1, prime);
if (g == 2) { // p mod 8 = 7 for g = 2;
BigInteger res = dhBI.mod(BigInteger.valueOf(8));
if (res.intValue() != 7) {
return false;
}
} else if (g == 3) { // p mod 3 = 2 for g = 3;
BigInteger res = dhBI.mod(BigInteger.valueOf(3));
if (res.intValue() != 2) {
return false;
}
} else if (g == 5) { // p mod 5 = 1 or 4 for g = 5;
BigInteger res = dhBI.mod(BigInteger.valueOf(5));
int val = res.intValue();
if (val != 1 && val != 4) {
return false;
}
} else if (g == 6) { // p mod 24 = 19 or 23 for g = 6;
BigInteger res = dhBI.mod(BigInteger.valueOf(24));
int val = res.intValue();
if (val != 19 && val != 23) {
return false;
}
} else if (g == 7) { // p mod 7 = 3, 5 or 6 for g = 7.
BigInteger res = dhBI.mod(BigInteger.valueOf(7));
int val = res.intValue();
if (val != 3 && val != 5 && val != 6) {
return false;
}
}
String hex = bytesToHex(prime);
if (hex.equals("C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B")) {
return true;
}
BigInteger dhBI2 = dhBI.subtract(BigInteger.valueOf(1)).divide(BigInteger.valueOf(2));
return !(!dhBI.isProbablePrime(30) || !dhBI2.isProbablePrime(30));
}
public static boolean isGoodGaAndGb(BigInteger g_a, BigInteger p) {
return !(g_a.compareTo(BigInteger.valueOf(1)) != 1 || g_a.compareTo(p.subtract(BigInteger.valueOf(1))) != -1);
}
public static boolean arraysEquals(byte[] arr1, int offset1, byte[] arr2, int offset2) {
if (arr1 == null || arr2 == null || offset1 < 0 || offset2 < 0 || arr1.length - offset1 != arr2.length - offset2 || arr1.length - offset1 < 0 || arr2.length - offset2 < 0) {
return false;
}
boolean result = true;
for (int a = offset1; a < arr1.length; a++) {
if (arr1[a + offset1] != arr2[a + offset2]) {
result = false;
}
}
return result;
}
public static byte[] computeSHA1(byte[] convertme, int offset, int len) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(convertme, offset, len);
return md.digest();
} catch (Exception e) {
FileLog.e("messenger", e);
}
return new byte[20];
}
public static byte[] computeSHA1(ByteBuffer convertme, int offset, int len) {
int oldp = convertme.position();
int oldl = convertme.limit();
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
convertme.position(offset);
convertme.limit(len);
md.update(convertme);
return md.digest();
} catch (Exception e) {
FileLog.e("messenger", e);
} finally {
convertme.limit(oldl);
convertme.position(oldp);
}
return new byte[20];
}
public static byte[] computeSHA1(ByteBuffer convertme) {
return computeSHA1(convertme, 0, convertme.limit());
}
public static byte[] computeSHA1(byte[] convertme) {
return computeSHA1(convertme, 0, convertme.length);
}
public static byte[] computeSHA256(byte[] convertme, int offset, int len) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(convertme, offset, len);
return md.digest();
} catch (Exception e) {
FileLog.e("messenger", e);
}
return null;
}
public static long bytesToLong(byte[] bytes) {
return ((long) bytes[7] << 56) + (((long) bytes[6] & 0xFF) << 48) + (((long) bytes[5] & 0xFF) << 40) + (((long) bytes[4] & 0xFF) << 32)
+ (((long) bytes[3] & 0xFF) << 24) + (((long) bytes[2] & 0xFF) << 16) + (((long) bytes[1] & 0xFF) << 8) + ((long) bytes[0] & 0xFF);
}
public static String MD5(String md5) {
if (md5 == null) {
return null;
@@ -262,7 +141,7 @@ public class Utilities {
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
FileLog.e("messenger", e);
}
return null;
}
@@ -1,57 +1,37 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
import java.util.Locale;
public class VideoEditedInfo {
public long startTime;
public long endTime;
public int rotationValue;
public int originalWidth;
public int originalHeight;
public int originalBitrate;
public int resultWidth;
public int resultHeight;
public int bitrate;
public int resultBitrate;
public String originalPath;
public String getString() {
return String.format(Locale.US, "-1_%d_%d_%d_%d_%d_%d_%d_%d_%s", startTime, endTime, rotationValue, originalWidth, originalHeight, bitrate, resultWidth, resultHeight, originalPath);
}
public boolean parseString(String string) {
if (string.length() < 6) {
return false;
}
try {
String args[] = string.split("_");
if (args.length >= 10) {
startTime = Long.parseLong(args[1]);
endTime = Long.parseLong(args[2]);
rotationValue = Integer.parseInt(args[3]);
originalWidth = Integer.parseInt(args[4]);
originalHeight = Integer.parseInt(args[5]);
bitrate = Integer.parseInt(args[6]);
resultWidth = Integer.parseInt(args[7]);
resultHeight = Integer.parseInt(args[8]);
for (int a = 9; a < args.length; a++) {
if (originalPath == null) {
originalPath = args[a];
} else {
originalPath += "_" + args[a];
}
}
}
return true;
} catch (Exception e) {
FileLog.e("messenger", e);
}
return false;
}
}
@@ -1,80 +0,0 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
package com.b44t.messenger;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
public class VideoEncodingService extends Service implements NotificationCenter.NotificationCenterDelegate {
private NotificationCompat.Builder builder = null;
private String path = null;
private int currentProgress = 0;
public VideoEncodingService() {
super();
NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileUploadProgressChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.stopEncodingService);
}
public IBinder onBind(Intent arg2) {
return null;
}
public void onDestroy() {
stopForeground(true);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileUploadProgressChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.stopEncodingService);
FileLog.e("messenger", "destroy video service");
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.FileUploadProgressChanged) {
String fileName = (String)args[0];
if (path != null && path.equals(fileName)) {
Float progress = (Float) args[1];
Boolean enc = (Boolean) args[2];
currentProgress = (int)(progress * 100);
builder.setProgress(100, currentProgress, currentProgress == 0);
NotificationManagerCompat.from(ApplicationLoader.applicationContext).notify(4, builder.build());
}
} else if (id == NotificationCenter.stopEncodingService) {
String filepath = (String)args[0];
if (filepath == null || filepath.equals(path)) {
stopSelf();
}
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
path = intent.getStringExtra("path");
if (path == null) {
stopSelf();
return Service.START_NOT_STICKY;
}
FileLog.e("messenger", "start video service");
if (builder == null) {
builder = new NotificationCompat.Builder(ApplicationLoader.applicationContext);
builder.setSmallIcon(android.R.drawable.stat_sys_upload);
builder.setWhen(System.currentTimeMillis());
builder.setContentTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setTicker(LocaleController.getString("SendingVideo", R.string.SendingVideo));
builder.setContentText(LocaleController.getString("SendingVideo", R.string.SendingVideo));
}
currentProgress = 0;
builder.setProgress(100, currentProgress, currentProgress == 0);
startForeground(4, builder.build());
NotificationManagerCompat.from(ApplicationLoader.applicationContext).notify(4, builder.build());
return Service.START_NOT_STICKY;
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger;
@@ -13,12 +28,13 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.RemoteInput;
import android.util.Log;
public class WearReplyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ApplicationLoader.postInitApplication();
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput == null) {
return;
@@ -32,7 +48,8 @@ public class WearReplyReceiver extends BroadcastReceiver {
if (dialog_id == 0 || max_id == 0) {
return;
}
SendMessagesHelper.getInstance().sendMessageText(text.toString(), dialog_id, null, null, true, null, null);
MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false);
SendMessagesHelper.getInstance().sendMessageText(text.toString(), dialog_id, null);
MrMailbox.markseenChat((int)dialog_id);
NotificationsController.getInstance().removeSeenMessages();
}
}
@@ -1,10 +1,25 @@
/*
* This is the source code of Telegram for Android v. 3.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
/*******************************************************************************
*
* Copyright Nikolai Kudashov, 2013-2016.
*/
* Messenger Android Frontend
* (C) 2013-2016 Nikolai Kudashov
* (C) 2017 Björn Petersen
* Contact: r10s@b44t.com, http://b44t.com
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see http://www.gnu.org/licenses/ .
*
******************************************************************************/
package com.b44t.messenger.browser;
@@ -13,7 +28,6 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import com.b44t.messenger.FileLog;
import com.b44t.ui.LaunchActivity;
public class Browser {
@@ -40,7 +54,7 @@ public class Browser {
intent.putExtra(android.provider.Browser.EXTRA_APPLICATION_ID, context.getPackageName());
context.startActivity(intent);
} catch (Exception e) {
FileLog.e("messenger", e);
}
}
@@ -1,86 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* A {@link FrameLayout} that resizes itself to match a specified aspect ratio.
*/
public final class AspectRatioFrameLayout extends FrameLayout {
/**
* The {@link FrameLayout} will not resize itself if the fractional difference between its natural
* aspect ratio and the requested aspect ratio falls below this threshold.
* <p>
* This tolerance allows the view to occupy the whole of the screen when the requested aspect
* ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce
* the number of view layers that need to be composited by the underlying system, which can help
* to reduce power consumption.
*/
private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f;
private float videoAspectRatio;
public AspectRatioFrameLayout(Context context) {
super(context);
}
public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Set the aspect ratio that this view should satisfy.
*
* @param widthHeightRatio The width to height ratio.
*/
public void setAspectRatio(float widthHeightRatio) {
if (this.videoAspectRatio != widthHeightRatio) {
this.videoAspectRatio = widthHeightRatio;
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (videoAspectRatio == 0) {
// Aspect ratio not set.
return;
}
int width = getMeasuredWidth();
int height = getMeasuredHeight();
float viewAspectRatio = (float) width / height;
float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
// We're within the allowed tolerance.
return;
}
if (aspectDeformation > 0) {
height = (int) (width / videoAspectRatio);
} else {
width = (int) (height * videoAspectRatio);
}
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import java.io.IOException;
/**
* Thrown when a live playback falls behind the available media window.
*/
public final class BehindLiveWindowException extends IOException {
public BehindLiveWindowException() {
super();
}
public BehindLiveWindowException(String message) {
super(message);
}
}
@@ -1,146 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import com.b44t.messenger.exoplayer.util.Util;
import android.media.AudioFormat;
import android.media.MediaCodec;
import android.media.MediaExtractor;
/**
* Defines constants that are generally useful throughout the library.
*/
public final class C {
/**
* Represents an unknown microsecond time or duration.
*/
public static final long UNKNOWN_TIME_US = -1L;
/**
* Represents a microsecond duration whose exact value is unknown, but which should match the
* longest of some other known durations.
*/
public static final long MATCH_LONGEST_US = -2L;
/**
* The number of microseconds in one second.
*/
public static final long MICROS_PER_SECOND = 1000000L;
/**
* Represents an unbounded length of data.
*/
public static final int LENGTH_UNBOUNDED = -1;
/**
* The name of the UTF-8 charset.
*/
public static final String UTF8_NAME = "UTF-8";
/**
* @see MediaCodec#CRYPTO_MODE_AES_CTR
*/
@SuppressWarnings("InlinedApi")
public static final int CRYPTO_MODE_AES_CTR = MediaCodec.CRYPTO_MODE_AES_CTR;
/**
* @see AudioFormat#ENCODING_INVALID
*/
public static final int ENCODING_INVALID = AudioFormat.ENCODING_INVALID;
/**
* @see AudioFormat#ENCODING_PCM_8BIT
*/
public static final int ENCODING_PCM_8BIT = AudioFormat.ENCODING_PCM_8BIT;
/**
* @see AudioFormat#ENCODING_PCM_16BIT
*/
public static final int ENCODING_PCM_16BIT = AudioFormat.ENCODING_PCM_16BIT;
/**
* PCM encoding with 24 bits per sample.
*/
public static final int ENCODING_PCM_24BIT = 0x80000000;
/**
* PCM encoding with 32 bits per sample.
*/
public static final int ENCODING_PCM_32BIT = 0x40000000;
/**
* @see AudioFormat#ENCODING_AC3
*/
@SuppressWarnings("InlinedApi")
public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3;
/**
* @see AudioFormat#ENCODING_E_AC3
*/
@SuppressWarnings("InlinedApi")
public static final int ENCODING_E_AC3 = AudioFormat.ENCODING_E_AC3;
/**
* @see AudioFormat#ENCODING_DTS
*/
@SuppressWarnings("InlinedApi")
public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS;
/**
* @see AudioFormat#ENCODING_DTS_HD
*/
@SuppressWarnings("InlinedApi")
public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD;
/**
* @see AudioFormat#CHANNEL_OUT_7POINT1_SURROUND
*/
@SuppressWarnings({"InlinedApi", "deprecation"})
public static final int CHANNEL_OUT_7POINT1_SURROUND = Util.SDK_INT < 23
? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
/**
* @see MediaExtractor#SAMPLE_FLAG_SYNC
*/
@SuppressWarnings("InlinedApi")
public static final int SAMPLE_FLAG_SYNC = MediaExtractor.SAMPLE_FLAG_SYNC;
/**
* @see MediaExtractor#SAMPLE_FLAG_ENCRYPTED
*/
@SuppressWarnings("InlinedApi")
public static final int SAMPLE_FLAG_ENCRYPTED = MediaExtractor.SAMPLE_FLAG_ENCRYPTED;
/**
* Indicates that a sample should be decoded but not rendered.
*/
public static final int SAMPLE_FLAG_DECODE_ONLY = 0x8000000;
/**
* A return value for methods where the end of an input was encountered.
*/
public static final int RESULT_END_OF_INPUT = -1;
/**
* A return value for methods where the length of parsed data exceeds the maximum length allowed.
*/
public static final int RESULT_MAX_LENGTH_EXCEEDED = -2;
private C() {}
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
/**
* Maintains codec event counts, for debugging purposes only.
* <p>
* Counters should be written from the playback thread only. Counters may be read from any thread.
* To ensure that the counter values are correctly reflected between threads, users of this class
* should invoke {@link #ensureUpdated()} prior to reading and after writing.
*/
public final class CodecCounters {
public int codecInitCount;
public int codecReleaseCount;
public int inputBufferCount;
public int outputFormatChangedCount;
public int outputBuffersChangedCount;
public int renderedOutputBufferCount;
public int skippedOutputBufferCount;
public int droppedOutputBufferCount;
public int maxConsecutiveDroppedOutputBufferCount;
/**
* Should be invoked from the playback thread after the counters have been updated. Should also
* be invoked from any other thread that wishes to read the counters, before reading. These calls
* ensure that counter updates are made visible to the reading threads.
*/
public synchronized void ensureUpdated() {
// Do nothing. The use of synchronized ensures a memory barrier should another thread also
// call this method.
}
public String getDebugString() {
ensureUpdated();
StringBuilder builder = new StringBuilder();
builder.append("cic:").append(codecInitCount);
builder.append(" crc:").append(codecReleaseCount);
builder.append(" ibc:").append(inputBufferCount);
builder.append(" ofc:").append(outputFormatChangedCount);
builder.append(" obc:").append(outputBuffersChangedCount);
builder.append(" ren:").append(renderedOutputBufferCount);
builder.append(" sob:").append(skippedOutputBufferCount);
builder.append(" dob:").append(droppedOutputBufferCount);
builder.append(" mcdob:").append(maxConsecutiveDroppedOutputBufferCount);
return builder.toString();
}
}
@@ -1,116 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import com.b44t.messenger.exoplayer.util.Util;
import android.annotation.TargetApi;
import android.media.MediaExtractor;
/**
* Compatibility wrapper around {@link android.media.MediaCodec.CryptoInfo}.
*/
public final class CryptoInfo {
/**
* @see android.media.MediaCodec.CryptoInfo#iv
*/
public byte[] iv;
/**
* @see android.media.MediaCodec.CryptoInfo#key
*/
public byte[] key;
/**
* @see android.media.MediaCodec.CryptoInfo#mode
*/
public int mode;
/**
* @see android.media.MediaCodec.CryptoInfo#numBytesOfClearData
*/
public int[] numBytesOfClearData;
/**
* @see android.media.MediaCodec.CryptoInfo#numBytesOfEncryptedData
*/
public int[] numBytesOfEncryptedData;
/**
* @see android.media.MediaCodec.CryptoInfo#numSubSamples
*/
public int numSubSamples;
private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo;
public CryptoInfo() {
frameworkCryptoInfo = Util.SDK_INT >= 16 ? newFrameworkCryptoInfoV16() : null;
}
/**
* @see android.media.MediaCodec.CryptoInfo#set(int, int[], int[], byte[], byte[], int)
*/
public void set(int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
byte[] key, byte[] iv, int mode) {
this.numSubSamples = numSubSamples;
this.numBytesOfClearData = numBytesOfClearData;
this.numBytesOfEncryptedData = numBytesOfEncryptedData;
this.key = key;
this.iv = iv;
this.mode = mode;
if (Util.SDK_INT >= 16) {
updateFrameworkCryptoInfoV16();
}
}
/**
* Equivalent to {@link MediaExtractor#getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo)}.
*
* @param extractor The extractor from which to retrieve the crypto information.
*/
@TargetApi(16)
public void setFromExtractorV16(MediaExtractor extractor) {
extractor.getSampleCryptoInfo(frameworkCryptoInfo);
numSubSamples = frameworkCryptoInfo.numSubSamples;
numBytesOfClearData = frameworkCryptoInfo.numBytesOfClearData;
numBytesOfEncryptedData = frameworkCryptoInfo.numBytesOfEncryptedData;
key = frameworkCryptoInfo.key;
iv = frameworkCryptoInfo.iv;
mode = frameworkCryptoInfo.mode;
}
/**
* Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance.
* <p>
* Successive calls to this method on a single {@link CryptoInfo} will return the same instance.
* Changes to the {@link CryptoInfo} will be reflected in the returned object. The return object
* should not be modified directly.
*
* @return The equivalent {@link android.media.MediaCodec.CryptoInfo} instance.
*/
@TargetApi(16)
public android.media.MediaCodec.CryptoInfo getFrameworkCryptoInfoV16() {
return frameworkCryptoInfo;
}
@TargetApi(16)
private android.media.MediaCodec.CryptoInfo newFrameworkCryptoInfoV16() {
return new android.media.MediaCodec.CryptoInfo();
}
@TargetApi(16)
private void updateFrameworkCryptoInfoV16() {
frameworkCryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData, key, iv,
mode);
}
}
@@ -1,69 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import com.b44t.messenger.exoplayer.util.Util;
import android.annotation.TargetApi;
import android.media.MediaCodecInfo.CodecCapabilities;
/**
* Contains information about a media decoder.
*/
@TargetApi(16)
public final class DecoderInfo {
/**
* The name of the decoder.
* <p>
* May be passed to {@link android.media.MediaCodec#createByCodecName(String)} to create an
* instance of the decoder.
*/
public final String name;
/**
* {@link CodecCapabilities} for this decoder.
*/
public final CodecCapabilities capabilities;
/**
* Whether the decoder supports seamless resolution switches.
*
* @see android.media.MediaCodecInfo.CodecCapabilities#isFeatureSupported(String)
* @see android.media.MediaCodecInfo.CodecCapabilities#FEATURE_AdaptivePlayback
*/
public final boolean adaptive;
/**
* @param name The name of the decoder.
* @param capabilities {@link CodecCapabilities} of the decoder.
*/
/* package */ DecoderInfo(String name, CodecCapabilities capabilities) {
this.name = name;
this.capabilities = capabilities;
this.adaptive = isAdaptive(capabilities);
}
private static boolean isAdaptive(CodecCapabilities capabilities) {
return capabilities != null && Util.SDK_INT >= 19 && isAdaptiveV19(capabilities);
}
@TargetApi(19)
private static boolean isAdaptiveV19(CodecCapabilities capabilities) {
return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback);
}
}
@@ -1,278 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import com.b44t.messenger.exoplayer.upstream.Allocator;
import com.b44t.messenger.exoplayer.upstream.NetworkLock;
import android.os.Handler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* A {@link LoadControl} implementation that allows loads to continue in a sequence that prevents
* any loader from getting too far ahead or behind any of the other loaders.
* <p>
* Loads are scheduled so as to fill the available buffer space as rapidly as possible. Once the
* duration of buffered media and the buffer utilization both exceed respective thresholds, the
* control switches to a draining state during which no loads are permitted to start. During
* draining periods, resources such as the device radio have an opportunity to switch into low
* power modes. The control reverts back to the loading state when either the duration of buffered
* media or the buffer utilization fall below respective thresholds.
* <p>
* This implementation of {@link LoadControl} integrates with {@link NetworkLock}, by registering
* itself as a task with priority {@link NetworkLock#STREAMING_PRIORITY} during loading periods,
* and unregistering itself during draining periods.
*/
public final class DefaultLoadControl implements LoadControl {
/**
* Interface definition for a callback to be notified of {@link DefaultLoadControl} events.
*/
public interface EventListener {
/**
* Invoked when the control transitions from a loading to a draining state, or vice versa.
*
* @param loading Whether the control is now in a loading state.
*/
void onLoadingChanged(boolean loading);
}
public static final int DEFAULT_LOW_WATERMARK_MS = 15000;
public static final int DEFAULT_HIGH_WATERMARK_MS = 30000;
public static final float DEFAULT_LOW_BUFFER_LOAD = 0.2f;
public static final float DEFAULT_HIGH_BUFFER_LOAD = 0.8f;
private static final int ABOVE_HIGH_WATERMARK = 0;
private static final int BETWEEN_WATERMARKS = 1;
private static final int BELOW_LOW_WATERMARK = 2;
private final Allocator allocator;
private final List<Object> loaders;
private final HashMap<Object, LoaderState> loaderStates;
private final Handler eventHandler;
private final EventListener eventListener;
private final long lowWatermarkUs;
private final long highWatermarkUs;
private final float lowBufferLoad;
private final float highBufferLoad;
private int targetBufferSize;
private long maxLoadStartPositionUs;
private int bufferState;
private boolean fillingBuffers;
private boolean streamingPrioritySet;
/**
* Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class.
*
* @param allocator The {@link Allocator} used by the loader.
*/
public DefaultLoadControl(Allocator allocator) {
this(allocator, null, null);
}
/**
* Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class.
*
* @param allocator The {@link Allocator} used by the loader.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public DefaultLoadControl(Allocator allocator, Handler eventHandler,
EventListener eventListener) {
this(allocator, eventHandler, eventListener, DEFAULT_LOW_WATERMARK_MS,
DEFAULT_HIGH_WATERMARK_MS, DEFAULT_LOW_BUFFER_LOAD, DEFAULT_HIGH_BUFFER_LOAD);
}
/**
* Constructs a new instance.
*
* @param allocator The {@link Allocator} used by the loader.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param lowWatermarkMs The minimum duration of media that can be buffered for the control to
* be in the draining state. If less media is buffered, then the control will transition to
* the filling state.
* @param highWatermarkMs The minimum duration of media that can be buffered for the control to
* transition from filling to draining.
* @param lowBufferLoad The minimum fraction of the buffer that must be utilized for the control
* to be in the draining state. If the utilization is lower, then the control will transition
* to the filling state.
* @param highBufferLoad The minimum fraction of the buffer that must be utilized for the control
* to transition from the loading state to the draining state.
*/
public DefaultLoadControl(Allocator allocator, Handler eventHandler, EventListener eventListener,
int lowWatermarkMs, int highWatermarkMs, float lowBufferLoad, float highBufferLoad) {
this.allocator = allocator;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.loaders = new ArrayList<>();
this.loaderStates = new HashMap<>();
this.lowWatermarkUs = lowWatermarkMs * 1000L;
this.highWatermarkUs = highWatermarkMs * 1000L;
this.lowBufferLoad = lowBufferLoad;
this.highBufferLoad = highBufferLoad;
}
@Override
public void register(Object loader, int bufferSizeContribution) {
loaders.add(loader);
loaderStates.put(loader, new LoaderState(bufferSizeContribution));
targetBufferSize += bufferSizeContribution;
}
@Override
public void unregister(Object loader) {
loaders.remove(loader);
LoaderState state = loaderStates.remove(loader);
targetBufferSize -= state.bufferSizeContribution;
updateControlState();
}
@Override
public void trimAllocator() {
allocator.trim(targetBufferSize);
}
@Override
public Allocator getAllocator() {
return allocator;
}
@Override
public boolean update(Object loader, long playbackPositionUs, long nextLoadPositionUs,
boolean loading) {
// Update the loader state.
int loaderBufferState = getLoaderBufferState(playbackPositionUs, nextLoadPositionUs);
LoaderState loaderState = loaderStates.get(loader);
boolean loaderStateChanged = loaderState.bufferState != loaderBufferState
|| loaderState.nextLoadPositionUs != nextLoadPositionUs || loaderState.loading != loading;
if (loaderStateChanged) {
loaderState.bufferState = loaderBufferState;
loaderState.nextLoadPositionUs = nextLoadPositionUs;
loaderState.loading = loading;
}
// Update the buffer state.
int currentBufferSize = allocator.getTotalBytesAllocated();
int bufferState = getBufferState(currentBufferSize);
boolean bufferStateChanged = this.bufferState != bufferState;
if (bufferStateChanged) {
this.bufferState = bufferState;
}
// If either of the individual states have changed, update the shared control state.
if (loaderStateChanged || bufferStateChanged) {
updateControlState();
}
return currentBufferSize < targetBufferSize && nextLoadPositionUs != -1
&& nextLoadPositionUs <= maxLoadStartPositionUs;
}
private int getLoaderBufferState(long playbackPositionUs, long nextLoadPositionUs) {
if (nextLoadPositionUs == -1) {
return ABOVE_HIGH_WATERMARK;
} else {
long timeUntilNextLoadPosition = nextLoadPositionUs - playbackPositionUs;
return timeUntilNextLoadPosition > highWatermarkUs ? ABOVE_HIGH_WATERMARK :
timeUntilNextLoadPosition < lowWatermarkUs ? BELOW_LOW_WATERMARK :
BETWEEN_WATERMARKS;
}
}
private int getBufferState(int currentBufferSize) {
float bufferLoad = (float) currentBufferSize / targetBufferSize;
return bufferLoad > highBufferLoad ? ABOVE_HIGH_WATERMARK
: bufferLoad < lowBufferLoad ? BELOW_LOW_WATERMARK
: BETWEEN_WATERMARKS;
}
private void updateControlState() {
boolean loading = false;
boolean haveNextLoadPosition = false;
int highestState = bufferState;
for (int i = 0; i < loaders.size(); i++) {
LoaderState loaderState = loaderStates.get(loaders.get(i));
loading |= loaderState.loading;
haveNextLoadPosition |= loaderState.nextLoadPositionUs != -1;
highestState = Math.max(highestState, loaderState.bufferState);
}
fillingBuffers = !loaders.isEmpty() && (loading || haveNextLoadPosition)
&& (highestState == BELOW_LOW_WATERMARK
|| (highestState == BETWEEN_WATERMARKS && fillingBuffers));
if (fillingBuffers && !streamingPrioritySet) {
NetworkLock.instance.add(NetworkLock.STREAMING_PRIORITY);
streamingPrioritySet = true;
notifyLoadingChanged(true);
} else if (!fillingBuffers && streamingPrioritySet && !loading) {
NetworkLock.instance.remove(NetworkLock.STREAMING_PRIORITY);
streamingPrioritySet = false;
notifyLoadingChanged(false);
}
maxLoadStartPositionUs = -1;
if (fillingBuffers) {
for (int i = 0; i < loaders.size(); i++) {
Object loader = loaders.get(i);
LoaderState loaderState = loaderStates.get(loader);
long loaderTime = loaderState.nextLoadPositionUs;
if (loaderTime != -1
&& (maxLoadStartPositionUs == -1 || loaderTime < maxLoadStartPositionUs)) {
maxLoadStartPositionUs = loaderTime;
}
}
}
}
private void notifyLoadingChanged(final boolean loading) {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onLoadingChanged(loading);
}
});
}
}
private static class LoaderState {
public final int bufferSizeContribution;
public int bufferState;
public boolean loading;
public long nextLoadPositionUs;
public LoaderState(int bufferSizeContribution) {
this.bufferSizeContribution = bufferSizeContribution;
bufferState = ABOVE_HIGH_WATERMARK;
loading = false;
nextLoadPositionUs = -1;
}
}
}
@@ -1,77 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
/**
* A {@link TrackRenderer} that does nothing.
* <p>
* This renderer returns 0 from {@link #getTrackCount()} in order to request that it should be
* ignored. {@link IllegalStateException} is thrown from all other methods documented to indicate
* that they should not be invoked unless the renderer is prepared.
*/
public final class DummyTrackRenderer extends TrackRenderer {
@Override
protected boolean doPrepare(long positionUs) throws ExoPlaybackException {
return true;
}
@Override
protected int getTrackCount() {
return 0;
}
@Override
protected MediaFormat getFormat(int track) {
throw new IllegalStateException();
}
@Override
protected boolean isEnded() {
throw new IllegalStateException();
}
@Override
protected boolean isReady() {
throw new IllegalStateException();
}
@Override
protected void seekTo(long positionUs) {
throw new IllegalStateException();
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) {
throw new IllegalStateException();
}
@Override
protected void maybeThrowError() {
throw new IllegalStateException();
}
@Override
protected long getDurationUs() {
throw new IllegalStateException();
}
@Override
protected long getBufferedPositionUs() {
throw new IllegalStateException();
}
}
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
/**
* Thrown when a non-recoverable playback failure occurs.
* <p>
* Where possible, the cause returned by {@link #getCause()} will indicate the reason for failure.
*/
public final class ExoPlaybackException extends Exception {
/**
* True if the cause (i.e. the {@link Throwable} returned by {@link #getCause()}) was only caught
* by a fail-safe at the top level of the player. False otherwise.
*/
public final boolean caughtAtTopLevel;
public ExoPlaybackException(String message) {
super(message);
caughtAtTopLevel = false;
}
public ExoPlaybackException(Throwable cause) {
super(cause);
caughtAtTopLevel = false;
}
public ExoPlaybackException(String message, Throwable cause) {
super(message, cause);
caughtAtTopLevel = false;
}
/* package */ ExoPlaybackException(Throwable cause, boolean caughtAtTopLevel) {
super(cause);
this.caughtAtTopLevel = caughtAtTopLevel;
}
}
@@ -1,415 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import android.os.Looper;
/**
* An extensible media player exposing traditional high-level media player functionality, such as
* the ability to prepare, play, pause and seek.
*
* <p>Topics covered here are:
* <ol>
* <li><a href="#Assumptions">Assumptions and player composition</a>
* <li><a href="#Threading">Threading model</a>
* <li><a href="#State">Player state</a>
* </ol>
*
* <a name="Assumptions"></a>
* <h3>Assumptions and player construction</h3>
*
* <p>The implementation is designed to make no assumptions about (and hence impose no restrictions
* on) the type of the media being played, how and where it is stored, or how it is rendered.
* Rather than implementing the loading and rendering of media directly, {@link ExoPlayer} instead
* delegates this work to one or more {@link TrackRenderer}s, which are injected when the player
* is prepared. Hence {@link ExoPlayer} is capable of loading and playing any media for which a
* {@link TrackRenderer} implementation can be provided.
*
* <p>{@link MediaCodecAudioTrackRenderer} and {@link MediaCodecVideoTrackRenderer} can be used for
* the common cases of rendering audio and video. These components in turn require an
* <i>upstream</i> {@link SampleSource} to be injected through their constructors, where upstream
* is defined to denote a component that is closer to the source of the media. This pattern of
* upstream dependency injection is actively encouraged, since it means that the functionality of
* the player is built up through the composition of components that can easily be exchanged for
* alternate implementations. For example a {@link SampleSource} implementation may require a
* further upstream data loading component to be injected through its constructor, with different
* implementations enabling the loading of data from various sources.
*
* <a name="Threading"></a>
* <h3>Threading model</h3>
*
* <p>The figure below shows the {@link ExoPlayer} threading model.</p>
* <p align="center"><img src="../../../../../images/exoplayer_threading_model.png"
* alt="MediaPlayer state diagram"
* border="0"/></p>
*
* <ul>
* <li>It is recommended that instances are created and accessed from a single application thread.
* An application's main thread is ideal. Accessing an instance from multiple threads is
* discouraged, however if an application does wish to do this then it may do so provided that it
* ensures accesses are synchronized.
* </li>
* <li>Registered {@link Listener}s are invoked on the thread that created the {@link ExoPlayer}
* instance.</li>
* <li>An internal playback thread is responsible for managing playback and invoking the
* {@link TrackRenderer}s in order to load and play the media.</li>
* <li>{@link TrackRenderer} implementations (or any upstream components that they depend on) may
* use additional background threads (e.g. to load data). These are implementation specific.</li>
* </ul>
*
* <a name="State"></a>
* <h3>Player state</h3>
*
* <p>The components of an {@link ExoPlayer}'s state can be divided into two distinct groups. State
* accessed by {@link #getSelectedTrack(int)} and {@link #getPlayWhenReady()} is only ever
* changed by invoking the player's methods, and are never changed as a result of operations that
* have been performed asynchronously by the playback thread. In contrast, the playback state
* accessed by {@link #getPlaybackState()} is only ever changed as a result of operations
* completing on the playback thread, as illustrated below.</p>
* <p align="center"><img src="../../../../../images/exoplayer_state.png"
* alt="ExoPlayer state"
* border="0"/></p>
*
* <p>The possible playback state transitions are shown below. Transitions can be triggered either
* by changes in the state of the {@link TrackRenderer}s being used, or as a result of
* {@link #prepare(TrackRenderer[])}, {@link #stop()} or {@link #release()} being invoked.</p>
* <p align="center"><img src="../../../../../images/exoplayer_playbackstate.png"
* alt="ExoPlayer playback state transitions"
* border="0"/></p>
*/
public interface ExoPlayer {
/**
* A factory for instantiating ExoPlayer instances.
*/
public static final class Factory {
/**
* The default minimum duration of data that must be buffered for playback to start or resume
* following a user action such as a seek.
*/
public static final int DEFAULT_MIN_BUFFER_MS = 2500;
/**
* The default minimum duration of data that must be buffered for playback to resume
* after a player invoked rebuffer (i.e. a rebuffer that occurs due to buffer depletion, and
* not due to a user action such as starting playback or seeking).
*/
public static final int DEFAULT_MIN_REBUFFER_MS = 5000;
private Factory() {}
/**
* Obtains an {@link ExoPlayer} instance.
* <p>
* Must be invoked from a thread that has an associated {@link Looper}.
*
* @param rendererCount The number of {@link TrackRenderer}s that will be passed to
* {@link #prepare(TrackRenderer[])}.
* @param minBufferMs A minimum duration of data that must be buffered for playback to start
* or resume following a user action such as a seek.
* @param minRebufferMs A minimum duration of data that must be buffered for playback to resume
* after a player invoked rebuffer (i.e. a rebuffer that occurs due to buffer depletion, and
* not due to a user action such as starting playback or seeking).
*/
public static ExoPlayer newInstance(int rendererCount, int minBufferMs, int minRebufferMs) {
return new ExoPlayerImpl(rendererCount, minBufferMs, minRebufferMs);
}
/**
* Obtains an {@link ExoPlayer} instance.
* <p>
* Must be invoked from a thread that has an associated {@link Looper}.
*
* @param rendererCount The number of {@link TrackRenderer}s that will be passed to
* {@link #prepare(TrackRenderer[])}.
*/
public static ExoPlayer newInstance(int rendererCount) {
return new ExoPlayerImpl(rendererCount, DEFAULT_MIN_BUFFER_MS, DEFAULT_MIN_REBUFFER_MS);
}
}
/**
* Interface definition for a callback to be notified of changes in player state.
*/
public interface Listener {
/**
* Invoked when the value returned from either {@link ExoPlayer#getPlayWhenReady()} or
* {@link ExoPlayer#getPlaybackState()} changes.
*
* @param playWhenReady Whether playback will proceed when ready.
* @param playbackState One of the {@code STATE} constants defined in the {@link ExoPlayer}
* interface.
*/
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
/**
* Invoked when the current value of {@link ExoPlayer#getPlayWhenReady()} has been reflected
* by the internal playback thread.
* <p>
* An invocation of this method will shortly follow any call to
* {@link ExoPlayer#setPlayWhenReady(boolean)} that changes the state. If multiple calls are
* made in rapid succession, then this method will be invoked only once, after the final state
* has been reflected.
*/
void onPlayWhenReadyCommitted();
/**
* Invoked when an error occurs. The playback state will transition to
* {@link ExoPlayer#STATE_IDLE} immediately after this method is invoked. The player instance
* can still be used, and {@link ExoPlayer#release()} must still be called on the player should
* it no longer be required.
*
* @param error The error.
*/
void onPlayerError(ExoPlaybackException error);
}
/**
* A component of an {@link ExoPlayer} that can receive messages on the playback thread.
* <p>
* Messages can be delivered to a component via {@link ExoPlayer#sendMessage} and
* {@link ExoPlayer#blockingSendMessage}.
*/
public interface ExoPlayerComponent {
/**
* Handles a message delivered to the component. Invoked on the playback thread.
*
* @param messageType An integer identifying the type of message.
* @param message The message object.
* @throws ExoPlaybackException If an error occurred whilst handling the message.
*/
void handleMessage(int messageType, Object message) throws ExoPlaybackException;
}
/**
* The player is neither prepared or being prepared.
*/
public static final int STATE_IDLE = 1;
/**
* The player is being prepared.
*/
public static final int STATE_PREPARING = 2;
/**
* The player is prepared but not able to immediately play from the current position. The cause
* is {@link TrackRenderer} specific, but this state typically occurs when more data needs
* to be buffered for playback to start.
*/
public static final int STATE_BUFFERING = 3;
/**
* The player is prepared and able to immediately play from the current position. The player will
* be playing if {@link #getPlayWhenReady()} returns true, and paused otherwise.
*/
public static final int STATE_READY = 4;
/**
* The player has finished playing the media.
*/
public static final int STATE_ENDED = 5;
/**
* A value that can be passed as the second argument to {@link #setSelectedTrack(int, int)} to
* disable the renderer.
*/
public static final int TRACK_DISABLED = -1;
/**
* A value that can be passed as the second argument to {@link #setSelectedTrack(int, int)} to
* select the default track.
*/
public static final int TRACK_DEFAULT = 0;
/**
* Represents an unknown time or duration.
*/
public static final long UNKNOWN_TIME = -1;
/**
* Gets the {@link Looper} associated with the playback thread.
*
* @return The {@link Looper} associated with the playback thread.
*/
public Looper getPlaybackLooper();
/**
* Register a listener to receive events from the player. The listener's methods will be invoked
* on the thread that was used to construct the player.
*
* @param listener The listener to register.
*/
public void addListener(Listener listener);
/**
* Unregister a listener. The listener will no longer receive events from the player.
*
* @param listener The listener to unregister.
*/
public void removeListener(Listener listener);
/**
* Returns the current state of the player.
*
* @return One of the {@code STATE} constants defined in this interface.
*/
public int getPlaybackState();
/**
* Prepares the player for playback.
*
* @param renderers The {@link TrackRenderer}s to use. The number of renderers must match the
* value that was passed to the {@link ExoPlayer.Factory#newInstance} method.
*/
public void prepare(TrackRenderer... renderers);
/**
* Returns the number of tracks exposed by the specified renderer.
*
* @param rendererIndex The index of the renderer.
* @return The number of tracks.
*/
public int getTrackCount(int rendererIndex);
/**
* Returns the format of a track.
*
* @param rendererIndex The index of the renderer.
* @param trackIndex The index of the track.
* @return The format of the track.
*/
public MediaFormat getTrackFormat(int rendererIndex, int trackIndex);
/**
* Selects a track for the specified renderer.
*
* @param rendererIndex The index of the renderer.
* @param trackIndex The index of the track. A negative value or a value greater than or equal to
* the renderer's track count will disable the renderer.
*/
public void setSelectedTrack(int rendererIndex, int trackIndex);
/**
* Returns the index of the currently selected track for the specified renderer.
*
* @param rendererIndex The index of the renderer.
* @return The selected track. A negative value or a value greater than or equal to the renderer's
* track count indicates that the renderer is disabled.
*/
public int getSelectedTrack(int rendererIndex);
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
* If the player is already in this state, then this method can be used to pause and resume
* playback.
*
* @param playWhenReady Whether playback should proceed when ready.
*/
public void setPlayWhenReady(boolean playWhenReady);
/**
* Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
*
* @return Whether playback will proceed when ready.
*/
public boolean getPlayWhenReady();
/**
* Whether the current value of {@link ExoPlayer#getPlayWhenReady()} has been reflected by the
* internal playback thread.
*
* @return True if the current value has been reflected. False otherwise.
*/
public boolean isPlayWhenReadyCommitted();
/**
* Seeks to a position specified in milliseconds.
*
* @param positionMs The seek position.
*/
public void seekTo(long positionMs);
/**
* Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention
* is to pause playback.
* <p>
* Calling this method will cause the playback state to transition to
* {@link ExoPlayer#STATE_IDLE}. The player instance can still be used, and
* {@link ExoPlayer#release()} must still be called on the player if it's no longer required.
* <p>
* Calling this method does not reset the playback position. If this player instance will be used
* to play another video from its start, then {@code seekTo(0)} should be called after stopping
* the player and before preparing it for the next video.
*/
public void stop();
/**
* Releases the player. This method must be called when the player is no longer required.
* <p>
* The player must not be used after calling this method.
*/
public void release();
/**
* Sends a message to a specified component. The message is delivered to the component on the
* playback thread. If the component throws a {@link ExoPlaybackException}, then it is
* propagated out of the player as an error.
*
* @param target The target to which the message should be delivered.
* @param messageType An integer that can be used to identify the type of the message.
* @param message The message object.
*/
public void sendMessage(ExoPlayerComponent target, int messageType, Object message);
/**
* Blocking variant of {@link #sendMessage(ExoPlayerComponent, int, Object)} that does not return
* until after the message has been delivered.
*
* @param target The target to which the message should be delivered.
* @param messageType An integer that can be used to identify the type of the message.
* @param message The message object.
*/
public void blockingSendMessage(ExoPlayerComponent target, int messageType, Object message);
/**
* Gets the duration of the track in milliseconds.
*
* @return The duration of the track in milliseconds, or {@link ExoPlayer#UNKNOWN_TIME} if the
* duration is not known.
*/
public long getDuration();
/**
* Gets the current playback position in milliseconds.
*
* @return The current playback position in milliseconds.
*/
public long getCurrentPosition();
/**
* Gets an estimate of the absolute position in milliseconds up to which data is buffered.
*
* @return An estimate of the absolute position in milliseconds up to which data is buffered,
* or {@link ExoPlayer#UNKNOWN_TIME} if no estimate is available.
*/
public long getBufferedPosition();
/**
* Gets an estimate of the percentage into the media up to which data is buffered.
*
* @return An estimate of the percentage into the media up to which data is buffered. 0 if the
* duration of the media is not known or if no estimate is available.
*/
public int getBufferedPercentage();
}
@@ -1,230 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.b44t.messenger.exoplayer;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.util.Arrays;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Concrete implementation of {@link ExoPlayer}.
*/
/* package */ final class ExoPlayerImpl implements ExoPlayer {
private static final String TAG = "ExoPlayerImpl";
private final Handler eventHandler;
private final ExoPlayerImplInternal internalPlayer;
private final CopyOnWriteArraySet<Listener> listeners;
private final MediaFormat[][] trackFormats;
private final int[] selectedTrackIndices;
private boolean playWhenReady;
private int playbackState;
private int pendingPlayWhenReadyAcks;
/**
* Constructs an instance. Must be invoked from a thread that has an associated {@link Looper}.
*
* @param rendererCount The number of {@link TrackRenderer}s that will be passed to
* {@link #prepare(TrackRenderer[])}.
* @param minBufferMs A minimum duration of data that must be buffered for playback to start
* or resume following a user action such as a seek.
* @param minRebufferMs A minimum duration of data that must be buffered for playback to resume
* after a player invoked rebuffer (i.e. a rebuffer that occurs due to buffer depletion, and
* not due to a user action such as starting playback or seeking).
*/
@SuppressLint("HandlerLeak")
public ExoPlayerImpl(int rendererCount, int minBufferMs, int minRebufferMs) {
Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION);
this.playWhenReady = false;
this.playbackState = STATE_IDLE;
this.listeners = new CopyOnWriteArraySet<>();
this.trackFormats = new MediaFormat[rendererCount][];
this.selectedTrackIndices = new int[rendererCount];
eventHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
ExoPlayerImpl.this.handleEvent(msg);
}
};
internalPlayer = new ExoPlayerImplInternal(eventHandler, playWhenReady, selectedTrackIndices,
minBufferMs, minRebufferMs);
}
@Override
public Looper getPlaybackLooper() {
return internalPlayer.getPlaybackLooper();
}
@Override
public void addListener(Listener listener) {
listeners.add(listener);
}
@Override
public void removeListener(Listener listener) {
listeners.remove(listener);
}
@Override
public int getPlaybackState() {
return playbackState;
}
@Override
public void prepare(TrackRenderer... renderers) {
Arrays.fill(trackFormats, null);
internalPlayer.prepare(renderers);
}
@Override
public int getTrackCount(int rendererIndex) {
return trackFormats[rendererIndex] != null ? trackFormats[rendererIndex].length : 0;
}
@Override
public MediaFormat getTrackFormat(int rendererIndex, int trackIndex) {
return trackFormats[rendererIndex][trackIndex];
}
@Override
public void setSelectedTrack(int rendererIndex, int trackIndex) {
if (selectedTrackIndices[rendererIndex] != trackIndex) {
selectedTrackIndices[rendererIndex] = trackIndex;
internalPlayer.setRendererSelectedTrack(rendererIndex, trackIndex);
}
}
@Override
public int getSelectedTrack(int rendererIndex) {
return selectedTrackIndices[rendererIndex];
}
@Override
public void setPlayWhenReady(boolean playWhenReady) {
if (this.playWhenReady != playWhenReady) {
this.playWhenReady = playWhenReady;
pendingPlayWhenReadyAcks++;
internalPlayer.setPlayWhenReady(playWhenReady);
for (Listener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState);
}
}
}
@Override
public boolean getPlayWhenReady() {
return playWhenReady;
}
@Override
public boolean isPlayWhenReadyCommitted() {
return pendingPlayWhenReadyAcks == 0;
}
@Override
public void seekTo(long positionMs) {
internalPlayer.seekTo(positionMs);
}
@Override
public void stop() {
internalPlayer.stop();
}
@Override
public void release() {
internalPlayer.release();
eventHandler.removeCallbacksAndMessages(null);
}
@Override
public void sendMessage(ExoPlayerComponent target, int messageType, Object message) {
internalPlayer.sendMessage(target, messageType, message);
}
@Override
public void blockingSendMessage(ExoPlayerComponent target, int messageType, Object message) {
internalPlayer.blockingSendMessage(target, messageType, message);
}
@Override
public long getDuration() {
return internalPlayer.getDuration();
}
@Override
public long getCurrentPosition() {
return internalPlayer.getCurrentPosition();
}
@Override
public long getBufferedPosition() {
return internalPlayer.getBufferedPosition();
}
@Override
public int getBufferedPercentage() {
long bufferedPosition = getBufferedPosition();
long duration = getDuration();
return bufferedPosition == ExoPlayer.UNKNOWN_TIME || duration == ExoPlayer.UNKNOWN_TIME ? 0
: (int) (duration == 0 ? 100 : (bufferedPosition * 100) / duration);
}
// Not private so it can be called from an inner class without going through a thunk method.
/* package */ void handleEvent(Message msg) {
switch (msg.what) {
case ExoPlayerImplInternal.MSG_PREPARED: {
System.arraycopy(msg.obj, 0, trackFormats, 0, trackFormats.length);
playbackState = msg.arg1;
for (Listener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState);
}
break;
}
case ExoPlayerImplInternal.MSG_STATE_CHANGED: {
playbackState = msg.arg1;
for (Listener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState);
}
break;
}
case ExoPlayerImplInternal.MSG_SET_PLAY_WHEN_READY_ACK: {
pendingPlayWhenReadyAcks--;
if (pendingPlayWhenReadyAcks == 0) {
for (Listener listener : listeners) {
listener.onPlayWhenReadyCommitted();
}
}
break;
}
case ExoPlayerImplInternal.MSG_ERROR: {
ExoPlaybackException exception = (ExoPlaybackException) msg.obj;
for (Listener listener : listeners) {
listener.onPlayerError(exception);
}
break;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More