Giter Site home page Giter Site logo

tmo1 / sms-ie Goto Github PK

View Code? Open in Web Editor NEW
273.0 11.0 33.0 10.1 MB

SMS Import / Export is a simple Android app that imports and exports SMS and MMS messages, call logs, and contacts from and to JSON / NDJSON files.

License: GNU General Public License v3.0

Kotlin 90.47% Python 9.53%
sms export import android backup mms json restore call-logs contacts

sms-ie's Introduction

SMS Import / Export

GitHub Release GitHub Release Date - Published_At F-Droid Version

GitHub issues GitHub closed issues GitHub commit activity

SMS Import / Export is a simple Android app that imports and exports SMS and MMS messages, call logs, and contacts from and to (ND)JSON files. (Contacts import and export are currently functional but considered experimental.) Root is not required.

Get it on F-Droid

Changes In Version 2.0.0

Version 2.0.0 introduced a major rewrite of the SMS and MMS messages import / export code, implementing a new message storage format (v2):

  • The messages are now stored in a Newline-delimited JSON file (always named messages.ndjson), as opposed to the standard JSON previously used.

  • Binary MMS data is now stored separately from message text data and metadata; the messages.ndjson file, along with a data/ directory containing the MMS binary data files copied directly from the Android filesystem (with their original filenames), are both encapsulated in a ZIP file.

  • All (ND)JSON tags added by SMS Import / Export are now prefixed with a double underscore (e.g., __display_name, __parts), to clearly indicate that they have been added by the app.

For a discussion of the advantages and disadvantages of the new format over the old one (v1), see here.

The NDJSON file is not as human-readable as the previous pretty-printed JSON file, due to the necessary absence of newlines within each JSON message record, but this is easily rectified by feeding the NDJSON to the jq tool, which will pretty-print it:

~$ jq < messages.ndjson

These format changes unfortunately render versions of the app from 2.0.0 and on incompatible with JSON message files produced by earlier versions of the app. Several solutions to this incompatibility are possible:

  • An earlier version of the app (with a 1.x.x version number) can be used to import messages in v1 format.

  • Where feasible, a current version of the app can be used to re-export the messages to v2 format.

  • A conversion tool to convert message files from v1 to v2 format is available here (documented here). This tool is experimental, and has not been extensively tested.

The above applies only to SMS and MMS messages; the format for call logs and contacts is currently unchanged, although they may be switched to the new format in the future.

Installation

SMS Import / Export is available from Github. Releases, which include pre-built APK packages, can be downloaded from the Releases page, and are also available at F-Droid. Automatically built (debug) packages of the latest code pushed to the repository are generally available here (click on the latest workflow run, then click on com.github.tmo1.sms_ie in the Artifacts section).

For instructions on building the app from its source code, see BUILDING.md.

Compatibility

Current versions of SMS Import / Export should run on any Android (phone-like) device running KitKat / 4.4 (API level 19) or later, although message import and scheduled message export are only possible on devices running Marshmallow / 6.0 (API level 23) or later.

The app is tested primarily on stock Android and LineageOS, but should generally run on other versions of Android as well.

Usage

  • Import or export messages, call log, or contacts: Click the respective button, then select an import or export source or destination.

  • Wipe messages: Click the Wipe Messages button, then confirm by pressing the Wipe button in the pop-up dialog box.

These operations may take some time for large numbers of messages, calls, or contacts. The app will report the total number of SMS and MMS messages, calls, or contacts imported or exported, and the elapsed time, upon successful conclusion.

By default, binary MMS data (such as images and videos) are exported. The user can choose to exclude them, which will often result in a much smaller ZIP file.

Note that upon import or wipe, message apps present on the system may not immediately correctly reflect the new state of the message database due to app caching and / or local storage. This can be resolved by clearing such cache and storage, e.g. Settings / Apps / Messaging / Storage & cache / Clear storage | Clear cache.

Import / Export Locations

SMS Import / Export does all input and output via the Android Storage Access Framework (SAF). The app should thus be able to import from and export to any location available via the SAF, including both local storage (internal, SD card, or USB attached) as well as cloud storage accessible through the SAF, via either a dedicated app (e.g., the Nextcloud Android App) or Rclone through RSAF.

Encryption

SMS Import / Export does not have any internal encryption / decryption functionality, and there are currently no plans to add such functionality. Instead, the currently recommended method for automatic encryption / decryption is to use an Rclone crypt remote via RSAF to transparently encrypt data as it is exported and decrypt it as it is imported. (The RSAF developer explains how to do this here, but cautions that he would only suggest this method for those already familiar with Rclone.) Note that this method will only work for internal storage or cloud storage accessible via Rclone, but not for SD card or USB attached storage.

Importing Messages

Subscription IDs

SMS Import / Export tries to preserve as much data and metadata as possible upon import. Android includes a sub_id (Subscription ID) field in both SMS and MMS message metadata. Earlier versions of the app included these sub_ids when importing, but this can cause messages to disappear on Android 14 (issue #128, Reddit), so the current default is to set all sub_ids to -1 upon import (negative values indicate that "the sub id cannot be determined"). The old behavior is still available via a settings toggle.

Additionally, some MMS part metadata apparently contain a sub_id field as well (despite the absence of any mention of this in the API documentation), and attempting to import these sub_ids can cause the app to crash. These sub_ids are currently handled the same way as the ones in the SMS and MMS metadata.

Deduplication

SMS Import / Export can attempt to deduplicate messages and call log entries upon import. If this feature is enabled in the app's settings, the app will check all new messages and call log entries against all existing messages and call log entries in the respective databases (including those messages and call log entries already inserted earlier in the import process) and ignore those it considers to be duplicates of ones already in the databases. This feature is currently considered experimental; it has not been extensively tested, and may yield both false positives and false negatives, and is accordingly not enabled by default. Deduplication of contacts is not currently implemented.

If this feature is not enabled, no deduplication is done. For example, if messages are exported and then immediately reimported, the device will then contain two copies of every message. To avoid this, the device can be wiped of all messages before importing by using the "Wipe Messages" button. The call log can be cleared via the standard phone app: select "Call history" from the app's ellipsis menu, then select "Clear call history" from the call history ellipsis menu.

SMS Import / Export cannot directly deduplicate messages or call log entries already present in the Android databases, but it should be possible to use the app to perform such deduplication by first exporting messages / call log, then wiping messages / clearing the call history, and finally re-importing the exported messages / call log.

Implementation

Message deduplication is tricky, since on the one hand, unlike email messages, SMS and MMS messages do not generally have a unique Message-ID, while on the other hand, some message metadata (e.g., THREAD_ID) does not remain constant when messages are moved around, and some metadata is not present for all messages. SMS Import / Export therefore tries to identify duplicate messages by comparing carefully chosen message data and metadata fields and concludes that two messages are identical if the compared fields are. Currently, SMS messages are assumed to be identical if they have identical ADDRESS, TYPE, DATE, and BODY fields, and MMS messages are assumed to be identical if they have identical DATE and MESSAGE_BOX fields, plus identical MESSAGE_ID fields if that field is present in the new message, or identical CONTENT_LOCATION fields if that field is present in the new message and MESSAGE_ID is not.

Call log deduplication works similarly but is simpler: call log entries are assumed to be identical if they have identical NUMBER, TYPE, and DATE fields.

Scheduled Export

To enable the scheduled export of messages, call logs and / or contacts, enable the feature in the app's Settings, and select a time to export at and a directory to export to. (Optionally, select which of the various data types to export.) The app will then attempt to export the selected data to a new, datestamped file or files in the selected directory every day at the selected time. (See the TODO section below.)

Running As A Foreground Service

On recent versions of Android, scheduled exports that export many MMS messages or that run for more than ten minutes may be killed by the system. To avoid this, scheduled exports can be run as a foreground service, which requires disabling battery optimizations for the app. (See issue #129 / PR #131.)

Retention

When scheduled exports are enabled, the following options can be used to control retention:

  • Delete old exports - If this option is not enabled (the default), then any old exports will be left untouched (i.e., all exports are retained indefinitely). If it is enabled, then for each data type (contacts, call log, and messages), upon successful export, the app will try to delete any old exports (i.e., all files with names of the form <data-type>-<yyyy-MM-dd>.[zip|json], where <data-type> is the data type successfully exported, and <yyyy-MM-dd> is a datestamp). Selective retention of a subset of old exports can be accomplished by enabling this option in conjunction with the use of external software with snapshotting and selective retention functionality, such as rsnapshot or borg, running either on the local device, or on a system to which the exports are synced via software such as Syncthing. This software should be scheduled to run between exports, and configured to preserve copies of the previous exports before the app deletes them following its next scheduled exports.

  • Remove datestamps from filenames - Scheduled exports are always initially created with filenames of the form <data-type>-<yyyy-MM-dd>.[zip|json]. If this option is enabled (in addition to the previous one), then after attempting to delete all old exports (of the relevant data type), the app will then attempt to remove the datestamp from the current export's filename by renaming it to <data-type>.[zip|json]. This is intended to make successive exports appear to be different versions of the same file, which may be useful in conjunction with external software that implements some form of file versioning, such as Syncthing or Nextcloud.

Permissions

To export messages, permission to read SMSs and Contacts is required (the need for the latter is explained below). The app will ask for these permissions on startup, if it does not already have them.

To import or wipe messages, SMS Import / Export must be the default messaging app. This is due to an Android design decision.

Warning

While an app is the default messaging app, it takes full responsibility for handling incoming SMS and MMS messages, and if does not store them, they will be lost. SMS Import / Export ignores incoming messages, so in order to avoid losing such messages, the device it is running on should be disconnected from the network (by putting it into airplane mode, or similar means) before the app is made the default messaging app, and only reconnected to the network after a proper messaging app is made the default.

To export call logs, permission to read Call Logs and Contacts is required (the need for the latter is explained below). Currently, the app does not ask permission to read Call Logs, and it must be granted by the user on his own initiative.

To import call logs, permission to read and write Call Logs is required.

To export contacts, permission to read Contacts is required.

To import contacts, permission to write Contacts is required. (Granting the app permission to access Contacts grants both read and write permission, although if the app is upgraded from an earlier version which did not declare that it uses permission to write Contacts, then it may be necessary to deny and re-grant Contacts permission in order to enable permission to write Contacts.)

To post notifications regarding the result(s) of a scheduled export run, permission to post notifications is required on Android 13 (API level 33) and later.

To run scheduled exports as a foreground service, permission to disable battery optimizations for the app is required (see Running As A Foreground Service).

Contacts

SMS and MMS messages include phone numbers ("addresses") but not the names of the communicating parties. The contact information displayed by Android is generated by cross-referencing phone numbers with the device's Contacts database. When exporting messages, SMS Import / Export does this cross-referencing in order to include the contact names in its output; this is why permission to read Contacts in necessary. When importing, included contact names are ignored, since the app (at least currently) does not add entries to or modify the Android Contacts database during message import. The best way to maintain the association of messages with contacts is to separately transfer contacts to the device into which SMS Import / Export is importing messages, via either SMS Import / Export's contacts export / import functionality or Android's built in contacts export / import functionality. Contacts cross-referencing is performed for call log export as well, despite the fact that call log metadata will often already include the contact name; see below for a discussion of this point.

(ND)JSON Structure

Following is the structure of the (ND)JSON currently exported by SMS Import / Export; this is subject to change in future versions of the app.

Messages

The exported NDJSON is a series of lines, each consisting of a JSON object representing a message, SMSs followed by MMSs. Each JSON message object contains a series of tag-value pairs taken directly from Android's internal message data / metadata structures, documented in the Android API Reference: SMS, MMS. In addition, SMS Import / Export adds some other tag-value pairs and child JSON objects, as described below. (All tags added by the app to message JSON objects and their children are prefixed with a double underscore ("__") to clearly indicate that they have been added by the app and are not present in Android's message structures.)

SMS Messages

In SMS messages, the value of type specifies (among other things) the direction of the message: the two most common values are 1, denoting "inbox" (i.e., received), and 2, denoting "sent".

SMS messages contain a single address tag; depending on the message direction, this is either the sender or receiver address. SMS Import / Export attempts to look up the address in the Android Contacts database. If this is successful, a tag-value pair of the form "__display_name": "Alice" is added to the SMS message object.

MMS Messages

MMS message objects have the following additions to the tag-value pairs of their internal Android MMS representation:

  • A tag-value pair of the form "__sender_address": { ... }

  • A tag-value pair of the form "__recipient_addresses": [ { ... }, { ... } ]. The child JSON objects associated with __sender_address and __recipient_addresses contain a series of tag-value pairs taken directly from Android's internal MMS address structure, documented here, plus possibly a single added tag-value pair of the form "__display_name": "Alice", as with SMS messages.

  • A tag-value pair of the form "__parts": [ { ... }, { ... }], where the child JSON objects contain a series of tag-value pairs taken directly from Android's internal MMS part structure, documented here.

Android stores binary data of MMS parts as individual files in its filesystem. SMS Import / Export copies these files directly into a data/ directory in the ZIP file, retaining their original filenames (without the full path). The association of these files with MMS parts is based on the values of the _DATA tags of the MMS parts. (SMS Import / Export utilizes only the actual filename (the last segment of the path) for this association. If there is a problem accessing the binary data, then the data may not be present.)

Call Logs

The exported JSON is an array of JSON objects representing calls. Each JSON call object contains a series of tag-value pairs taken directly from Android's internal call metadata structures, documented in the Android API Reference. In addition, SMS Import / Export will try to add a display-name tag, as with SMS and MMS messages. The call logs may already have a CACHED_NAME (name) field, but the app will still try to add a display-name, since the documentation of the CACHED_NAME field states:

The cached name associated with the phone number, if it exists.

This value is typically filled in by the dialer app for the caching purpose, so it's not guaranteed to be present, and may not be current if the contact information associated with this number has changed.

Contacts

As explained in the official documentation, Android stores contacts in a complex system of three related database tables:

SMS Import / Export simply dumps these tables in structured JSON format, resulting in a rather cluttered representation of the data with a great deal of repetition and redundancy. This is in accordance with the design principles of the app, which prioritize making sure that no useful information is excluded from the export, and avoiding the code complexity and coding time that would be necessary to filter and / or reorganize the raw data.

The exported JSON is an array of JSON objects representing aggregated contacts, each containing a series of tag-value pairs taken directly from the Contacts table. To each contact JSON object, a tag-value pair of the form "raw_contacts": [ { ... }, { ... }] is added, where the child JSON objects represent the (aggregated) contacts' associated raw contacts, and each contain a series of tag-value pairs taken directly from the RawContacts table. To each raw contact JSON object, a tag-value pair of the form "contacts_data": [ { ... }, { ... }] is added, where the child JSON objects represent the raw contacts' associated data (i.e., the actual details of the contacts, such as phone numbers, postal mail addresses, and email addresses), and each contain a series of tag-value pairs taken directly from the Data table.

Currently, social stream data, contact groups, and contact photos are not exported.

Contacts import and export is currently considered experimental, and the JSON format is subject to change.

Note: Currently, when contacts are exported and then imported, the app may report a larger total of contacts imported than exported. This is due to the fact that when exporting, the total number of Contacts exported is reported (since this is a logical and straightforward thinng to do), whereas when importing, the total number of Raw Contacts imported is reported (since as per the documentation, applications are not allowed to add Contacts, only Raw Contacts, and as noted above, a Contact may consist of an aggregation of multiple Raw Contacts).

Limitations

Contacts

Contacts import only imports basic contact data (name, phone numbers, email and postal addresses, etc.), but not the contacts metadata that Android stores. Additionally, imported contacts are not associated with the accounts with which they had been associated on the system from which they were exported, and the user has no control over which account they will be associated with on the target system; all contacts are inserted into the target system's default account.

Call logs

Voicemail entries are skipped on call log import (see issue #110).

Call Log Maximum Capacity

Although this is apparently not publicly officially documented, Android's Call Log has a fixed maximum number of calls that it will store (500 in many / most versions of Android, 1000 in API 30 (version 11) on a Pixel [my own experience, corroborated here]).

Earlier versions of this document stated that:

Attempting to import calls when the log is full may fail, in which case the app will not report an error, but the reported number of imported calls will be lower then the number of calls provided for import. E.g., if calls are exported from a phone with a full log, and the output file is then imported to the same phone, the app will report 0 calls imported.

This was a misinterpretation of observed call import failures, which were actually caused by a bug in the app, which has since been fixed.

Bugs, Feature Requests, and Other Issues

Bugs, feature requests, and other issues can be filed at the SMS Import / Export issue tracker. When reporting any problem with the app, please try to reproduce the problem with the latest release of the app, and please specify the versions of the app used for export and / or import, as applicable.

Posting JSON / ZIP Files

When reporting a problem with import or export functionality, please try to include the (ND)JSON file involved, in accordance with the following guidelines:

Minimal Reproducible Example

Please try to reproduce the problem with as small a (ND)JSON file as possible. The simplest way to reduce the size of the file is to use the app's Settings / Debugging options / Maximum records ... option to export only a small number of messages.

Redaction

It is strongly recommended to redact any posted (ND)JSON and remove any sensitive information. To help automate this process (currently, for message collections only), a Python script redact-messages.py is available. It has no external dependencies beyond a standard Python environment. It expects a collection of messages in the NDJSON format used by SMS Import / Export on standard input, and writes a redacted version of the same to standard output:

~$ ./redact-messages.py < messages.ndjson > messages-redacted.ndjson

โš ๏ธThere is no guarantee that this script will correctly and completely redact all sensitive information. It as provided as is, with no warranty. If the JSON in question contains any particularly sensitive information, do not rely on this script to redact it. Note that the script does not consider sensitive certain metadata, such as message timestamps, that might be considered sensitive in some contexts.

Logcat

When reporting a problem, particularly a reproducible one, please attach a logcat (a collection of log messages produced by Android - see here and here). If feasible, please reproduce the problem in a debug build of the latest code (see the Installation section of this README for an easy way to obtain such a build) and include the logcat from that, since the debug builds have more detailed logging. Instructions for obtaining a logcat (with increasing level of detail) can be found here, here, and here.

Known Issues

MIUI

When importing messages that have been exported from a MIUI system into a MIUI system, the following error may be encountered:

java.lang.IllegalArgumentException: The non-sync-callers AND non-blocked-url should not specify DELETED for inserting.

For a possible solution, see here.

SMS Messages With Multiple Recipients

SMS messages with multiple recipients are currently not handled entirely correctly; see issue #159 for details and the current status of support for such messages.

Translations

SMS Import / Export has been translated (from the original English) into the following languages (note that some of these translations may contain inaccuracies, due to changes to the app's original text since they were made):

Translation status

To add a translation into a new language, or to correct, update, or improve an existing translation, see here.

TODO

The following are various features and improvements to the app that have been suggested and may be implemented in the future:

  • Greater flexibility of scheduled exporting, including intervals other than daily, incremental / differential exporting, and retention handling (discussion in issue #7)

Contributing

For information about contributing to SMS Import / Export, and a list of contributors, see here.

Privacy

SMS Import / Export does no tracking, advertising, or phoning home. No user data is stored or transmitted anywhere except as explicitly designated by the user.

sms-db

SMS Import / Export is a sibling project to sms-db, a Linux tool to build an SQLite database out of collections of SMS and MMS messages in various formats. sms-db will hopefully eventually be able to import ZIP files created by SMS Import / Export, and to export its database to ZIP files that can be imported by SMS Import / Export.

Background

Coming from a procedural, command line interface, synchronous, Linux, Perl and Python background, the development of SMS Import / Export served as a crash course in object-oriented, graphical user interface, asynchronous, Android, Kotlin programming, and consequently entailed a fair amount of amateurishness and cargo cult programming. After much work and learning, however, the app does seem to function correctly and effectively.

Donations

SMS Import / Export is absolutely free software, and there is no expectation of any sort of compensation or support for the project. That being said, if anyone wishes to donate (to Thomas More, the app's primary author), this can be done via the Ko-fi platform.

License

SMS Import / Export is free / open source software, released under the terms of the GNU GPLv3 or later.

sms-ie's People

Contributors

andr5w avatar antonindelfabbro avatar artem13327 avatar baitmooth avatar baturax avatar biswa96 avatar chenxiaolong avatar codingjourney avatar comradekingu avatar donnnno avatar epicorange avatar merlignux avatar nautilusx avatar ngocanhtve avatar nhman-python avatar oersen avatar pjammo avatar poipoipoipoipoipoipoipoipoi avatar poussinou avatar sxwxs avatar tmo1 avatar vbh avatar yangyangdaji avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sms-ie's Issues

[feature] Periodic backup support

It'll be nice to see some sort of automatic backup feature at user-defined time intervals if it's in the scope. I currently use Super Backup for just that.

Export to directory should be always available

ATM, "Export to Directory" configuration is only available if you have "enable scheduled export" ON.

But I think it would make sense to be able to define the export directory to any export/import cases (not just for "scheduled export")

Progress meter?

Could there be a progress meter for importing and exporting messages? I don't mind waiting hours for messages to be imported as long as I know the process hasn't crashed.

Bug? I cannot import *any* file

Hi,

I just exported my SMS messages using your program. After placing the SD card with the export JSON file in my new phone, activating the app as default SMS app, I still cannot import it!

Every file I see in the Files Manager app is greyed out thus not accessible!? Do you have an explanation? I also tried to copy it to internal memory, but didn't help.

Importing contacts requires permission to write Contacts

Hello,

I have used SMS Import / Export to EXPORT CONTACTS and that works fine. However, when I try to IMPORT CONTACTS, I get the message "Importing contacts requires permission to write Contacts" (I don't even get a prompt for the location of the import file).
I get the same behaviour on Android 12 and LineageOS 19.
I have tried uninstalling the App > Installing a lower version = no luck, same message.
I have denied the App access to Contacts > Opened the app > Granted the app permissions to Contacts = no luck, same message.

Same behaviour on App Version: 1.5.1 and 1.5

Am I missing something? Can you please help?

Thank you

sms-ie crash when trying import

Hello, i'm using lineageos 18.1 and when i'm trying to import my .json file the apps shutdown. I made the export on the oneplus3 of my brother, his system was official oxygenOS (in android 8.0). I made 2 export, one with binary an the other one without the binary, both doesn't work.
Once i made the export i updated the op3 oxygenOS android 8.0 to lineageos 18.1 (android 11). Do you have idea why i can't export the .json files ?

The apps sometimes works well, and sometimes it doesn't works and the apps crash and close directly when i try to import. I''m always runing on lineageos 18.1.

optionally wipe sms database before restoring

Thanks for writing this utility. I'm trying to restore a large number of SMS/MMS (~3.5GB json file) from a samsung galaxy to a google pixel. I've restarted this process a few times and unfortunately I now have a bunch of duplicated messages. I've tried various other apps to delete these messages as well as using adb (adb shell pm clear com.android.providers.telephony) none of which seem to work.

Since sms-ie can inject messages, it'd be great if it could clear the database before loading new messages.

Automatically encrypt exported files

Hello:

It would be very useful if the app had an encryption module.
For an independent backup, a password could be entered when launching the backup.
For a scheduled backup, a password could be stored in the scheduling settings.
The password would be asked when restauring a backup.

With this functionality I would be confident in activating scheduled backup stored in my SD card and/or in a cloud service.

Thanks in advance!

Do not crash if mms part data is not exist

When i export messages with "Include (encoded) binary MMS data", i get fatal error:

07-30 22:41:37.675  7582  7582 D MediaScannerReceiver: action: android.intent.action.MEDIA_SCANNER_SCAN_FILE path: /storage/emulated/0/backup/messages.json
07-30 22:41:37.715  5454  5454 E AndroidRuntime: FATAL EXCEPTION: main
07-30 22:41:37.715  5454  5454 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 5454
07-30 22:41:37.715  5454  5454 E AndroidRuntime: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:144)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:698)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1410)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1247)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at android.content.ContentResolver.openInputStream(ContentResolver.java:967)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at com.github.tmo1.sms_ie.ImportExportKt.mmsToJSON(ImportExport.kt:374)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at com.github.tmo1.sms_ie.ImportExportKt.access$mmsToJSON(ImportExport.kt:1)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at com.github.tmo1.sms_ie.ImportExportKt$mmsToJSON$1.invokeSuspend(Unknown Source:17)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
07-30 22:41:37.715  5454  5454 E AndroidRuntime:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
07-30 22:41:37.719  1243  2063 W ActivityManager:   Force finishing activity com.github.tmo1.sms_ie/.MainActivity
07-30 22:41:37.723  1243  2063 E LightsService: Light requested not available on this device. 2
07-30 22:41:37.726  1243  2063 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:966 com.android.server.am.AppErrors.crashApplicationInner:393 com.android.server.am.AppErrors.crashApplication:321 com.android.server.am.ActivityManagerService.handleApplicationCrashInner:14489 com.android.server.am.ActivityManagerService.handleApplicationCrash:14471 
07-30 22:41:37.728  1243  1262 I ActivityManager: Showing crash dialog for package com.github.tmo1.sms_ie u0

Tail in messages.json:

    "parts": [
      {
        "_id": "6",
        "mid": "5",
        "seq": "-1",
        "ct": "application/smil",
        "cid": "<smil>",
        "cl": "smil.xml",
        "text": "<smil>...</smil>"
      },
      {
        "_id": "7",
        "mid": "5",
        "seq": "0",
        "ct": "image/jpeg",
        "cid": "<image000000>",
        "cl": "image000000.jpg",
        "_data": "/data/user_de/0/com.android.providers.telephony/app_parts/PART_1617028091818_image000000.jpg"

Probably it's because the file doesn't exist:

/data/user_de/0/com.android.providers.telephony/app_parts # ls PART_1617028091818_image000000.jpg
ls: PART_1617028091818_image000000.jpg: No such file or directory

Without "Include (encoded) binary MMS data" all works fine.

MMS not imported/exported correctly

When importing my messages on an old phone, none of the MMS imported appear correctly. The SMS apps I tested show that a message exists, from the correct contact and sent or received at the correct time. However, the message itself does not appear.

The app does show that MMS is being backed up when exporting and importing. Regular SMS messages from the same backups don't seem to be affected.
Screenshot_20221201-213346

Quality of contact photos after import

Question. As you probably know, exporting and importing contacts along with photos causes the quality of the photos to be degraded. With one import, there is not much difference. However, after several imports, you can see that the photo is of poor quality (compressed).
Do you know why this happens? Is this also happening in your application?

Unfortunately, I haven't had a chance to test it yet.
BTW. i described this problem a long time ago on xda
https://forum.xda-developers.com/t/app-4-0-true-phone-best-dialer-contact-manager-replacement.2934816/post-83062639
(Unfortunately the links to the photos are out of date)

(binary) MMS and SMS restore to separate threads

MMS from the same sender/receiver conversations are restored to two separate threads: one containing the SMS and the other containing the binary attachment. This means the actual text of the conversation is unattached from the attachment, so you end up with a thread of just images.

Unable to Export

Hi, I needed a no-nonsense app to export all my SMS messages to an open format as a backup before wiping this phone, and this looks like just what I need.
Unfortunately I'm not able to export at all. The app closes a few seconds after starting the export, and a 0-byte JSON file is written.
I'm on vanilla Android 11 on a Pixel 2XL.
I get this exception in logcat:

 5003 28074 E DatabaseUtils: Writing exception to parcel
08-23 11:38:51.585 25003 28074 E DatabaseUtils: java.lang.IllegalArgumentException: URI: content://com.android.contacts/phone_lookup/, calling user: com.github.tmo1.sms_ie, calling package:com.github.tmo1.sms_ie
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at com.android.providers.contacts.LegacyApiSupport.query(LegacyApiSupport.java:1836)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at com.android.providers.contacts.ContactsProvider2.queryLocal(ContactsProvider2.java:6950)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at com.android.providers.contacts.ContactsProvider2.queryDirectoryIfNecessary(ContactsProvider2.java:5445)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at com.android.providers.contacts.ContactsProvider2.query(ContactsProvider2.java:5387)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at android.content.ContentProvider.query(ContentProvider.java:1475)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at android.content.ContentProvider$Transport.query(ContentProvider.java:278)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:106)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at android.os.Binder.execTransactInternal(Binder.java:1154)
08-23 11:38:51.585 25003 28074 E DatabaseUtils: 	at android.os.Binder.execTransact(Binder.java:1123)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: FATAL EXCEPTION: main
08-23 11:38:51.611 31581 31581 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 31581
08-23 11:38:51.611 31581 31581 E AndroidRuntime: java.lang.IllegalArgumentException: URI: content://com.android.contacts/phone_lookup/, calling user: com.github.tmo1.sms_ie, calling package:com.github.tmo1.sms_ie
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.content.ContentProviderProxy.query(ContentProviderNative.java:472)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.content.ContentResolver.query(ContentResolver.java:1183)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.content.ContentResolver.query(ContentResolver.java:1115)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at android.content.ContentResolver.query(ContentResolver.java:1071)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at com.github.tmo1.sms_ie.MainActivity$smsToJson$2.invokeSuspend(MainActivity.kt:186)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
08-23 11:38:51.611 31581 31581 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

I thought that the query was perhaps failing because of a missing number or the like.
I went through my messages and deleted every conversation that wasn't a "normal" contact, such as ones from Verizon "900040001000", 5 digit senders, and Google, but I still get this same exception.
As far as I can tell, all the conversations left are normal stored contacts or phone numbers.

If there's any other debugging or information I can give, let me know (Although I do need to proceed with wiping and re-flashing this phone at some point).

Importing contacts requires permission to write Contacts

Hi,

Sorry, I have to create a new issue, as I can't re-open #69

Please see my note to #69 :

Hi,

Thank you for your reply.

Since the latest release I could find is 1.5.1 (https://github.com/tmo1/sms-ie/releases), and your commit is after the release of 1.5.1, I tried building with "gradlew assembleDebug" (as per the Installation Readme). I've cloned this repo, installed gradle, ran ./gradlew assembleDebug from the root of the cloned repo and I started getting build errors - first being about missing the ANDROID_HOME environment variable in local.properties, which I defined (and created the directory), then the build failed because I need to accept SDK licence agreements and install the Android Studio SDK Manager.

At this stage, I was wondering if it's possible to get the apk file including your changes from somewhere (so I can just install and test the functionality)?

I'm afraid trying to build the file myself, might lead me down a rabbit hole, spending a lot of time just configuring the build environment.

So, if it's possible, could I please grab the apk build containing your changes from somewhere? or I can wait for the new release if a new release is planned for the near future.

Thanks again!

Crash trying to import

Hey there,
Have been trying out the app to export a couple of databases and to merge them by importing back, but when pushing the "Import" button, choosing any previously exported json, the app crashes instantly.

I'm on Android 11 (LineageOS) and have given permissions for both SMS and contacts, and set the app as the default for messaging. The mmssms.db is empty and the OS is freshly installed.

Thanks!

Edit: Just realised there was an issue (#11 closed) already here. Maybe it's the same thing? I'll do a logcat and get back to you.

Exporting contacts crash

The first time worked, but not as expected (only one contact exported). I have multiple Google accounts with different contacts at each.
The second time I tried, the app crashed. Each time after I get this error:

FATAL EXCEPTION: main
Process: com.github.tmo1.sms_ie, PID: 15940
android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK[0]): Unable to convert BLOB to string
	at android.database.CursorWindow.nativeGetString(Native Method)
	at android.database.CursorWindow.getString(CursorWindow.java:480)
	at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53)
	at android.database.CursorWrapper.getString(CursorWrapper.java:141)
	at com.github.tmo1.sms_ie.ImportExportContactsKt.contactsToJSON(ImportExportContacts.kt:135)
	at com.github.tmo1.sms_ie.ImportExportContactsKt.access$contactsToJSON(ImportExportContacts.kt:1)
	at com.github.tmo1.sms_ie.ImportExportContactsKt$contactsToJSON$1.invokeSuspend(Unknown Source:13)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Crash at try import messages in Android 11

Is a *.json- source- file from a epistolaire-backup ( https://github.com/hydrargyrum/epistolaire ) unusable because of its possible own structure?
Which app, able to running in 4.4 kitkat, can spend a well backup?

Or may this new rules cause it? :
https://www.xda-developers.com/android-11-all-files-access-permission-form/

Is this a possible solution?
(The app has to ask for permission):
https://stackoverflow.com/questions/44772538/how-can-i-create-a-file-in-an-accessible-folder-on-android-non-root

Trigger sms export using adb?

Thank you for your work on this application! Is it possible to trigger an SMS export using adb?

My first guess would be to find where the sms-ie config is stored, and then to modify the export time to the upcoming minute. However, that seems a hacky work-around. Second thought was that perhaps there is some form of API for sms-ie that can be reached by adb.

Importing Contacts Creating Duplicate Entries

Recently went through contacts and did some name changes, I then exported contacts using the app and imported contacts on another phone. Some contacts show up as duplicate and I think it's only signal messaging app contacts

To reproduce the problem
Contact must be a signal contact

  1. Have no contacts
  2. Add new contact with their signal phone number and a random name
  3. Go to signal messaging app, find the number, you can see their name is not updated, click on their profile and click on contact details
  4. Go back to the contacts app, you should now see phone number and the option of using signal (could take a bit of time but you need to wait til you see signal messaging option)
  5. export the contacts (you will only see 1 contact exported)
  6. delete the contact of the number or all if you want (obviously make sure you have a backup if you deleted all contacts)
  7. import contacts (you will see 2 contacted imported)
  8. you now have 2 contacts with the same number and name

I wasn't able to reproduce the problem of them having different names but i was able to at least reproduce the double entries so hopefully fixing that fixes the name problem

Import verification

I don't know if this is worth the work, but here's the idea:

On the IMPORT operation, the default behaviour should always be to wipe all SMS/MMS/Contacts and then proceed to the new data import (this would solve the duplicates problem)

However BEFORE wiping, the app should verify/compare the data from the backup with that on the phone and warn the user if there will be any data loss (if yes, it should offer export).

Crash when importing .json file

When importing a .json file made as a backup on another phone, SMS Import/Export 1.3 (installed via F-Droid) immediately crashes without any error message.
Using a custom ROM (crdroid), I get this error log:

time: 1641484413465
msg: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getAuthority()' on a null object reference
stacktrace: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getAuthority()' on a null object reference
	at android.os.Parcel.createExceptionOrNull(Parcel.java:2379)
	at android.os.Parcel.createException(Parcel.java:2357)
	at android.os.Parcel.readException(Parcel.java:2340)
	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
	at android.content.ContentProviderProxy.insert(ContentProviderNative.java:549)
	at android.content.ContentResolver.insert(ContentResolver.java:2149)
	at android.content.ContentResolver.insert(ContentResolver.java:2111)
	at com.github.tmo1.sms_ie.MainActivity$importJson$2.invokeSuspend(MainActivity.kt:519)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Translate hebrow

I translated your app into Hebrew, this is the translation code
How can I send you a string?

Can't tell direction?

Is the direction information unavailable? I don't see any way to tell from the JSON.

I.e. if a message was one I sent or one I recieved.

F-Droid build failed

Execution failed for task ':app:lintVitalRelease'.
> Lint found fatal errors while assembling a release target.
  
  Fix the issues identified by lint, or create a baseline to see only new errors:

android {
lint {
baseline = file("lint-baseline.xml")
}
}


For more details, see https://developer.android.com/studio/write/lint#snapshot

Could you please take a look? Thanks!

Imported MMS are visible as just "white space"

Hello. I am trying to export/import messages from Motorola G6 Plus to OnePlus Nord 2 5G.
Telephone contains a lot of messages. About 13000 SMS and 1000 MMS.

I have gotten into two issues. If I tried to export everything from G6 Plus app crashes.

So I had just exported MMS using debug mode. Now when I import those messages in OnePlus Nord 2, it does show threads and "messages", but there are not any image visible, just empty spaces.

Can you let me know which information you want to share. Idealy in some private channel.

JSON format documentation

I'm the author of Epistolaire, an android app for exporting sms/mms to JSON. Unfortunately, it cannot import data yet.

To have better compatibility between our apps, I'm interested in what JSON format you use in your app. Epistolaire's format is described at https://github.com/hydrargyrum/epistolaire#json-format= and https://github.com/hydrargyrum/epistolaire/blob/master/backup.schema.json

Do you have a JSON schema description or a brief description? When importing, do you skip extra fields or do you reject the whole JSON?

This is related to another app which uses the same format as Epistolaire: hydrargyrum/breakthesilence#1

Out-of-memory crash when exporting MMS images

When exporting with the "Include (encoded) binary MMS data" checkbox checked, after running for about 20 seconds, the application crashes ("has stopped") due to running out of memory, leaving an empty JSON file. When the checkbox is unchecked, export completes without crashing and the JSON file contains valid data.

11-15 18:49:08.601 11485 12419 D ContactsProvider2ForLG: queryLocal match: 4000 return cursor
11-15 18:49:08.972 17914 17925 I zygote64: Background concurrent copying GC freed 4134(247KB) AllocSpace objects, 37(25MB) LOS objects, 23% free, 152MB/200MB, paused 7.609ms total 118.632ms
11-15 18:49:09.268 17914 17925 I zygote64: Background concurrent copying GC freed 1597(70KB) AllocSpace objects, 2(27MB) LOS objects, 19% free, 197MB/245MB, paused 31.778ms total 141.101ms
11-15 18:49:09.474 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.474 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.524 17914 18141 I zygote64: Alloc concurrent copying GC freed 637(45KB) AllocSpace objects, 1(36MB) LOS objects, 22% free, 161MB/209MB, paused 253us total 49.794ms
11-15 18:49:09.524 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.568 17914 18141 I zygote64: Alloc concurrent copying GC freed 6(16KB) AllocSpace objects, 0(0B) LOS objects, 22% free, 161MB/209MB, paused 296us total 43.477ms
11-15 18:49:09.568 17914 18141 I zygote64: Forcing collection of SoftReferences for 144MB allocation
11-15 18:49:09.568 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.652 17914 18141 I zygote64: Alloc concurrent copying GC freed 3611(127KB) AllocSpace objects, 0(0B) LOS objects, 22% free, 161MB/209MB, paused 288us total 83.743ms
11-15 18:49:09.652 17914 18141 W zygote64: Throwing OutOfMemoryError "Failed to allocate a 150994952 byte allocation with 50331648 free bytes and 94MB until OOM, max allowed footprint 219416160, growth limit 268435456"
11-15 18:49:09.652 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.652 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.693 17914 18141 I zygote64: Alloc concurrent copying GC freed 4(31KB) AllocSpace objects, 0(0B) LOS objects, 22% free, 161MB/209MB, paused 296us total 40.414ms
11-15 18:49:09.693 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.733 17914 18141 I zygote64: Alloc concurrent copying GC freed 3(16KB) AllocSpace objects, 0(0B) LOS objects, 22% free, 161MB/209MB, paused 286us total 40.092ms
11-15 18:49:09.733 17914 18141 I zygote64: Forcing collection of SoftReferences for 144MB allocation
11-15 18:49:09.733 17914 18141 I zygote64: Starting a blocking GC Alloc
11-15 18:49:09.817 17914 18141 I zygote64: Alloc concurrent copying GC freed 6(16KB) AllocSpace objects, 0(0B) LOS objects, 22% free, 161MB/209MB, paused 283us total 83.881ms
11-15 18:49:09.818 17914 18141 W zygote64: Throwing OutOfMemoryError "Failed to allocate a 150994952 byte allocation with 50331648 free bytes and 94MB until OOM, max allowed footprint 219416160, growth limit 268435456"
11-15 18:49:09.835 13042 13042 D MediaScannerReceiver: [MediaScanner] action: android.intent.action.MEDIA_SCANNER_SCAN_FILE
11-15 18:49:09.835 13042 13042 D MediaScannerReceiver: [MediaScanner] ACTION_MEDIA_SCANNER_SCAN_FILE
11-15 18:49:09.884 17914 17914 E AndroidRuntime: FATAL EXCEPTION: main
11-15 18:49:09.884 17914 17914 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 17914
11-15 18:49:09.884 17914 17914 E AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 150994952 byte allocation with 50331648 free bytes and 94MB until OOM, max allowed footprint 219416160, growth limit 268435456
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at java.util.Arrays.copyOf(Arrays.java:3260)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:125)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:660)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at java.lang.StringBuilder.append(StringBuilder.java:203)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONStringer.string(JSONStringer.java:344)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONStringer.value(JSONStringer.java:252)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONObject.writeTo(JSONObject.java:723)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONStringer.value(JSONStringer.java:237)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONArray.writeTo(JSONArray.java:613)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONStringer.value(JSONStringer.java:233)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONObject.writeTo(JSONObject.java:723)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONStringer.value(JSONStringer.java:237)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONArray.writeTo(JSONArray.java:613)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at org.json.JSONArray.toString(JSONArray.java:606)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at com.github.tmo1.sms_ie.MainActivity$smsToJson$2.invokeSuspend(MainActivity.kt:306)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
11-15 18:49:09.884 17914 17914 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
11-15 18:49:09.889  1510  2716 W ActivityManager:   Force finishing activity com.github.tmo1.sms_ie/.MainActivity

LG G6, Android 8.

I'm not an Android developer and haven't looked at Kotlin before, but it seems you're accumulating the entire JSON object in memory before writing anything to a file. If streaming writes are not possible, maybe you should write MMS binary data to separate files in small batches and leave it up to other software to join them based on the message ID.

send json backup to url

Hi,
It would be great if the app could allow to enter a url in the backup destination to send the json.

GUI/UX Improvement

I would like to suggest a GUI/UX improvement.

here is an idea:
backup1

Pressing More Options would take the user to:

backup2

I have not included the Wipe Messages because of #58 :)

This is just an idea!
I personally would like to see other ideas, if @tmo1 is into it, naturally :)

Call import fails due to UNIQUE constraint failure

Logcat:

2022-10-08 23:34:34.803 1331-1349/com.android.providers.blockednumber E/DatabaseUtils: Error inserting <REDACTED> into table  calls
    android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: calls._id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:938)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
        at android.database.DatabaseUtils$InsertHelper.insertInternal(DatabaseUtils.java:1306)
        at android.database.DatabaseUtils$InsertHelper.insert(DatabaseUtils.java:1431)
        at com.android.providers.contacts.DbModifierWithNotification.insert(DbModifierWithNotification.java:123)
        at com.android.providers.contacts.CallLogProvider.insertInternal(CallLogProvider.java:505)
        at com.android.providers.contacts.CallLogProvider.insert(CallLogProvider.java:449)
        at android.content.ContentProvider.insert(ContentProvider.java:1673)
        at android.content.ContentProvider$Transport.insert(ContentProvider.java:336)
        at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:167)
        at android.os.Binder.execTransactInternal(Binder.java:1159)
        at android.os.Binder.execTransact(Binder.java:1123)

Import Fails after ~27,000 SMS and ~21,000 MMS

I have a backup taken from an Asus Zenfone 8 Flip, running Android 12. JSON is about 15GB.
I've attempted the import twice. It gets through all ~27,000 SMS messages on import, however the application suddenly quits after it gets to around 21,000 MMS messages imported. That's out of about 48,000 MMS.

The JSON includes the binary data / images in the MMS as well.

Crash when export MMS.

12-28 22:29:05.550 21929 21929 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 21929
12-28 22:29:05.550 21929 21929 E AndroidRuntime: android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): Unable to convert BLOB to string
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at android.database.CursorWindow.nativeGetString(Native Method)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at android.database.CursorWindow.getString(CursorWindow.java:465)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:54)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at android.database.CursorWrapper.getString(CursorWrapper.java:203)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportMessagesKt.mmsToJSON(ImportExportMessages.kt:205)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportMessagesKt.access$mmsToJSON(ImportExportMessages.kt:1)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportMessagesKt$mmsToJSON$1.invokeSuspend(Unknown Source:17)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
12-28 22:29:05.550 21929 21929 E AndroidRuntime: Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@a5a2900, Dispatchers.Main]

veision:1.5.3

Importing contacts results in duplicates

The jq command returned 279 contacts as expected. Tried it in android emulator to import, 836 imported. And all the contacts are imported twice. Indeed, the first contact is correct (with image and all fields) and the second is completely empty, only the name-title is correct.

Originally posted by @thanasistrisp in #50 (comment)

Crash on export

Just installed to try it out, but it crashes in the middle of exporting SMS.

Anyways, here's the error from logcat:

07-05 18:07:32.831 20132 20132 E AndroidRuntime: FATAL EXCEPTION: main
07-05 18:07:32.831 20132 20132 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 20132
07-05 18:07:32.831 20132 20132 E AndroidRuntime: java.lang.NullPointerException: it.getString(addressIndex) must not be null
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at com.github.tmo1.sms_ie.ImportExportKt.smsToJSON(ImportExport.kt:243)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at com.github.tmo1.sms_ie.ImportExportKt.access$smsToJSON(ImportExport.kt:1)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at com.github.tmo1.sms_ie.ImportExportKt$smsToJSON$1.invokeSuspend(Unknown Source:17)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
07-05 18:07:32.831 20132 20132 E AndroidRuntime: 	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Make unique notification channel for the specific types

Currently the app uses one notification channel (named 'notification_channel') for every notification (scheduled backup successful, scheduled backup unsuccessful...etc).

It would be great to have the notifications seperated to unique channels to be able to enable/disable them seperately. (for example to be able to disable only the 'scheduled update successful' notifications ๐Ÿ˜‰)

Crash during export

I'm trying to export ~10000 SMS and ~5500 MMS from a phone that has been miraculously un-bricked (long, irrelevant story). The SMS portion of this task proceeds rapidly without issue. The MMS portion gets to message 780 or so and then the app closes and disappears abruptly without finishing.

I tried turning OFF the "Include (encoded) binary MMS data" option and the entire job runs to completion, however I would like to have the binary MMS data as well so this is not a solution.

I know very little about app development but it seems to me that the problem occurs inside ImportExportMessages.kt when an exception is thrown if there is a problem accessing the binary data.

It would be extremely helpful to me if this could fail more gracefully. I don't have the luxury of not having the corruption that seems to exist on that single message on this device.

I envision something like:

  1. prompting the user if they would like to proceed exporting without the missing binary data,
  2. printing a warning in the status line that the binary_data field is missing in some (or N) of the MMS messages,
  3. a debug toggle option in the settings that would allow the app to quietly drop missing MMS data

Any help would be greatly appreciated!

Enhancement: Catch JSON parsing errors during import and show in application

Hello, thanks for your application, I managed to import my several thousands text messages from about 14 years of using Nokia phones with Symbian now! Moreover, I like the fact that I can backup my messages using your application as well. However, I'd like to suggest to improve user friendliness of SMS IE by catching JSON parsing errors (and preferably other types of errors as well) and displaying some error message rather than simply crashing / dying. I had to create the import file by translating it to JSON from a CSV file (I created my own simple application running on a PC for that). While doing that, I had to discover and fix some bugs coming from differences in e.g. escaping certain characters in CSV and JSON, etc. However, I had to find these issues in the Android log retrieved using logcat rather than within the application, because the application simply crashed without providing any kind of feedback.

Crash at scheduled export at Nextcloud

When manually export no crash encountered. However, when I try to schedule export it crashes. I use android 11 and I try to save at nextcloud location from system picker. The error message is Export unsuccessful - see logcat for more details. However, when I choose a folder inside internal storage works perfectly.

Crash while exporting contacts

Hello, I keep getting crashes while trying to export contacts:

09-15 15:14:56.420 8622 8622 E AndroidRuntime: FATAL EXCEPTION: main
09-15 15:14:56.420 8622 8622 E AndroidRuntime: Process: com.github.tmo1.sms_ie, PID: 8622
09-15 15:14:56.420 8622 8622 E AndroidRuntime: android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): Unable to convert BLOB to string
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at android.database.CursorWindow.nativeGetString(Native Method)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at android.database.CursorWindow.getString(CursorWindow.java:469)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at android.database.CursorWrapper.getString(CursorWrapper.java:141)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportContactsKt.contactsToJSON(ImportExportContacts.kt:135)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportContactsKt.access$contactsToJSON(ImportExportContacts.kt:1)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at com.github.tmo1.sms_ie.ImportExportContactsKt$contactsToJSON$1.invokeSuspend(Unknown Source:13)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
09-15 15:14:56.420 8622 8622 E AndroidRuntime: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

The generated file ends with the following fragment within raw_contacts.contacts_data section (personal information replaced with XXXXX and YYYYYY):

      {
        "account_type": "com.google",
        "data_version": "2",
        "photo_file_id": "8",
        "display_name_alt": "XXXXXX",
        "sort_key_alt": "XXXXXX",
        "last_time_used": "0",
        "starred": "1",
        "has_phone_number": "1",
        "raw_contact_id": "1794",
        "carrier_presence": "0",
        "contact_last_updated_timestamp": "1662806182701",
        "photo_uri": "content://com.android.contacts/display_photo/8",
        "data_sync4": "12",
        "phonebook_bucket": "1",
        "times_used": "0",
        "display_name": "XXXXXX",
        "sort_key": "XXXXXX",
        "data_sync1": "3450259296 3450259296 Sync_High_Res",
        "version": "27",
        "data_sync2": "EhAzYjI0ODFlNjhlZWFjMTE5KAIwve_5eg==",
        "data_sync3": "EhAzYjI0ODFlNjhlZWFjMTE5KAIwve_5eg==",
        "photo_thumb_uri": "content://com.android.contacts/contacts/1794/photo",
        "in_default_directory": "1",
        "times_contacted": "0",
        "_id": "10658",
        "account_type_and_data_set": "com.google",
        "name_raw_contact_id": "1794",
        "phonebook_bucket_alt": "1",
        "last_time_contacted": "0",
        "pinned": "0",
        "is_primary": "1",
        "photo_id": "10658",
        "contact_id": "1794",
        "in_visible_group": "1",
        "phonebook_label": "A",
        "account_name": "YYYYYY",
        "display_name_source": "40",
        "dirty": "0",
        "sourceid": "3b2481e68eeac119",
        "phonetic_name_style": "0",
        "send_to_voicemail": "0",
        "lookup": "2322i3b2481e68eeac119",
        "phonebook_label_alt": "A",
        "is_super_primary": "0",
        "raw_contact_is_user_profile": "0",
        "mimetype": "vnd.android.cursor.item/photo",
        "data14": "8",
        "hash_id": "MrogkbdS2enmlQPtY66ALpUVE2Y=\n"

The referenced contact indeed has a photo attached to it (unlike some other contact which was exported to the file correctly).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.