Working
This commit is contained in:
		
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| # RCS Exporter | ||||
|  | ||||
| I've been using the app SMS Backup & Restore for years. After getting a new phone and transferring the messages over I noticed some were missing. | ||||
|  | ||||
| I tried to find out why this is happening - because of a "new" message type called RCS: https://en.wikipedia.org/wiki/Rich_Communication_Services | ||||
|  | ||||
| Essentially those messages are stored in a separate database on the phone, hence not considered regular text messages. | ||||
|  | ||||
| The above mentioned program is not able to export those messages (as of September 2021). | ||||
|  | ||||
| I didn't want to reinvent the wheel - there are already enough backup/restore apps for SMS and MMS. Instead I just wanted to be able to export the RCS messages, too. Preferably it should be a format the SMS BR can then import. | ||||
|  | ||||
| So if you're interested: | ||||
| 1. Backup your SMS and MMS messages with another program. | ||||
| 2. Import them on the target phone. | ||||
| 3. Export the RCS using this app. | ||||
| 4. Import those on the new phone as well. | ||||
|  | ||||
| Remarks: | ||||
| - This program has only been tested with text messages. I don't know if images, etc. can be exported as well. | ||||
| @@ -11,6 +11,7 @@ android { | ||||
|         targetSdk 30 | ||||
|         versionCode 1 | ||||
|         versionName "1.0" | ||||
|         useLibrary  'org.apache.http.legacy' | ||||
|  | ||||
|         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||||
|     } | ||||
|   | ||||
| @@ -27,6 +27,10 @@ | ||||
|                 <category android:name="android.intent.category.LAUNCHER" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|  | ||||
|         <!--        https://developer.android.com/about/versions/pie/android-9.0-changes-28#apache-p--> | ||||
|         <uses-library android:name="org.apache.http.legacy" android:required="false"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| @@ -1,29 +1,40 @@ | ||||
| package de.server47.smsexport; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.database.Cursor; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.util.Log; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.documentfile.provider.DocumentFile; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.OutputStream; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Calendar; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class MainActivity extends Activity | ||||
| { | ||||
|     Button bRead; | ||||
|     Button bRead, bWrite; | ||||
|  | ||||
|     final static int typeSMS = 0; | ||||
|     final static int typeMMS = 1; | ||||
|     final static int typeICS = 2; | ||||
|  | ||||
|     final static int requestCodeExport = 815; | ||||
|  | ||||
|     String contentToWrite = "bla"; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(@Nullable Bundle savedInstanceState) | ||||
|     { | ||||
| @@ -31,6 +42,7 @@ public class MainActivity extends Activity | ||||
|         setContentView(R.layout.main_activity); | ||||
|  | ||||
|         bRead = (Button)findViewById(R.id.bRead); | ||||
|         bWrite = (Button)findViewById(R.id.bWrite); | ||||
|  | ||||
|         bRead.setOnClickListener(new View.OnClickListener() | ||||
|         { | ||||
| @@ -48,37 +60,118 @@ public class MainActivity extends Activity | ||||
|                     export.append("backup_date=\"1631273111057\""); | ||||
|                     export.append("type=\"full\">"); | ||||
| //                    05.05.2001 19:15:00 | ||||
|                     String pattern = "dd-MM-yyyy H:m:s"; | ||||
|                     String pattern = "dd.MM.yyyy H:m:s"; | ||||
|                     SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); | ||||
|  | ||||
|                     for(int i = 0; i < response.size(); i++) | ||||
|                     { | ||||
|                         Calendar cal = Calendar.getInstance(); | ||||
|                         cal.setTimeInMillis(Long.parseLong(response.get(i).get("date"))); | ||||
|  | ||||
|                         /* | ||||
|                             type: 1 = inbound | ||||
|                             type: 2 = outbound | ||||
|                         */ | ||||
|  | ||||
|                         export.append( | ||||
|                 "<sms protocol=\"0\"" + | ||||
|                         "address=\"" + response.get(i).get("remote_uri").replace("tel:", "") + "\"" + | ||||
|                         "date=\"" + response.get(i).get("date") + "\"" + | ||||
|                         "type=\"1\"" + | ||||
|                         "subject=\"null\"" + | ||||
|                         "body=\"" + response.get(i).get("body") + "\"" + | ||||
|                         "toa=\"null\"" + | ||||
|                         "sc_toa=\"null\"" + | ||||
|                         "service_center=\"null\"" + | ||||
|                         "read=\"1\"" + | ||||
|                         "status=\"-1\"" + | ||||
|                         "locked=\"0\"" + | ||||
|                         "date_sent=\"0\"" + | ||||
|                         "sub_id=\"-1\"" + | ||||
|                         "readable_date=\"" + 05.05.2001 19:15:00 + "\"" + | ||||
|                         "contact_name=\"(Unknown)\"/>"; | ||||
|                         response.get(i).get() | ||||
|                             "<sms protocol=\"0\"" + | ||||
|                                 "address=\"" + response.get(i).get("remote_uri").replace("tel:", "") + "\"" + | ||||
|                                 "date=\"" + response.get(i).get("date") + "\"" + | ||||
|                                 "type=\"" + response.get(i).get("type") + "\"" + | ||||
|                                 "subject=\"null\"" + | ||||
|                                 "body=\"" + response.get(i).get("body") + "\"" + | ||||
|                                 "toa=\"null\"" + | ||||
|                                 "sc_toa=\"null\"" + | ||||
|                                 "service_center=\"null\"" + | ||||
|                                 "read=\"1\"" + | ||||
|                                 "status=\"-1\"" + | ||||
|                                 "locked=\"0\"" + | ||||
|                                 "date_sent=\"" + response.get(i).get("date_sent") + "\"" + | ||||
|                                 "sub_id=\"-1\"" + | ||||
|                                 "readable_date=\"" + simpleDateFormat.format(cal.getTime()) + "\"" + | ||||
|                                 "contact_name=\"(Unknown)\"/>" | ||||
|                         ); | ||||
|                     } | ||||
|  | ||||
|                     export.append("</smses>"); | ||||
|  | ||||
|                     contentToWrite = export.toString(); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         bWrite.setOnClickListener(new View.OnClickListener() | ||||
|         { | ||||
|             @Override | ||||
|             public void onClick(View v) | ||||
|             { | ||||
|                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); | ||||
|                 startActivityForResult(intent, requestCodeExport); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onActivityResult(int requestCode, int resultCode, Intent data) | ||||
|     { | ||||
|         super.onActivityResult(requestCode, resultCode, data); | ||||
|  | ||||
|         if(resultCode == RESULT_OK) | ||||
|         { | ||||
|             switch (requestCode) | ||||
|             { | ||||
|                 case requestCodeExport: | ||||
|                     if (resultCode == RESULT_OK) | ||||
|                     { | ||||
|                         Uri uriTree = data.getData(); | ||||
|                         exportFiles(uriTree, contentToWrite); | ||||
|                     } | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void exportFiles(Uri uriTree, String content) | ||||
|     { | ||||
|         String fileName = "Message_export_" + String.valueOf(Calendar.getInstance().getTimeInMillis()) + ".xml"; | ||||
|  | ||||
|         DocumentFile directory = DocumentFile.fromTreeUri(this, uriTree); | ||||
|  | ||||
|         // Clean up | ||||
| //        for(DocumentFile file : directory.listFiles()) | ||||
| //        { | ||||
| //            /* | ||||
| //                On some few users' devices it seems this caused a crash because file.getName() was null. | ||||
| //                The reason for that remains unknown, but we don't want the export to crash because of it. | ||||
| //             */ | ||||
| //            if(!StringUtils.isEmpty(file.getName())) | ||||
| //            { | ||||
| //                if (file.getName().equals(XmlFileInterface.settingsFileName) && file.canWrite()) | ||||
| //                    file.delete(); | ||||
| //                else if (file.getName().equals(prefsFileName) && file.canWrite()) | ||||
| //                    file.delete(); | ||||
| //            } | ||||
| //        } | ||||
|  | ||||
|         DocumentFile exportFile = directory.createFile("text/xml", fileName); | ||||
|  | ||||
|         if(exportFile.canWrite()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 OutputStream out = getApplicationContext().getContentResolver().openOutputStream(exportFile.getUri()); | ||||
|                 out.write(content.getBytes()); | ||||
|                 out.close(); | ||||
|  | ||||
|                 Toast.makeText(MainActivity.this, "Export complete.", Toast.LENGTH_LONG).show(); | ||||
|             } | ||||
|             catch (IOException e) | ||||
|             { | ||||
|                 e.printStackTrace(); | ||||
|                 Toast.makeText(MainActivity.this, "Error while writing file.", Toast.LENGTH_LONG).show(); | ||||
|             } | ||||
|         } | ||||
| //        else | ||||
| //            Toast.makeText(MainActivity.this, getResources().getString(R.string.ConfigurationExportError), Toast.LENGTH_LONG).show(); | ||||
|     } | ||||
|  | ||||
|     List<Map<String,String>> readMessages(int messageType) | ||||
|   | ||||
| @@ -2,8 +2,16 @@ | ||||
| <androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical" | ||||
|     android:layout_margin="@dimen/defaultMargin" | ||||
|     android:gravity="center_horizontal"> | ||||
|  | ||||
|     <TextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="@string/app_name" | ||||
|         android:textAppearance="@style/TextAppearance.MaterialComponents.Headline2" /> | ||||
|  | ||||
|     <Button | ||||
|         android:id="@+id/bRead" | ||||
|         android:layout_width="wrap_content" | ||||
| @@ -11,4 +19,11 @@ | ||||
|         android:layout_gravity="center" | ||||
|         android:text="Read" /> | ||||
|  | ||||
|     <Button | ||||
|         android:id="@+id/bWrite" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         android:text="Write" /> | ||||
|  | ||||
| </androidx.appcompat.widget.LinearLayoutCompat> | ||||
| @@ -1,3 +1,4 @@ | ||||
| <resources> | ||||
|     <dimen name="fab_margin">16dp</dimen> | ||||
|     <dimen name="defaultMargin">25px</dimen> | ||||
| </resources> | ||||
| @@ -1,5 +1,5 @@ | ||||
| <resources> | ||||
|     <string name="app_name">SmsExport</string> | ||||
|     <string name="app_name">RcsExport</string> | ||||
|     <string name="action_settings">Settings</string> | ||||
|     <!-- Strings used for fragments for navigation --> | ||||
|     <string name="first_fragment_label">First Fragment</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user