I'm making one sms backup and restore android app.
Unfortunately, my app cannot restore text messages on Xiaomi phones, including Redmi 3s with android 6, Redmi Note 11 with android 12, But in other phones, it performs SMS backup and restore operations very well.
How can I solve this bug?
Java codes:
public class SmsBackupActivity extends Activity {
private static final int DEF_SMS_REQ = 0;
Button btnBackup;
Button btnRestore;
AlertDialog dismiss;
SMSGettersSetters localSMSGettersSetters;
Cursor localCursor;
int i;
int j;
private static Context context;
ProgressDialog pDialog;
public List<SMSGettersSetters> smsBuffer = new ArrayList();
TextView tvLastBackup;
FileWriter write;
String[] xmlfile;
Uri localUri;
private void backupSMS() throws IOException {
this.smsBuffer.clear();
String str1 = getExternalFilesDir(null) + File.separator + "sms";
this.write = new FileWriter(str1 + File.separator + this.xmlfile[0] + ".xml");
localUri = Uri.parse("content://sms/");
ContentResolver localContentResolver = getContentResolver();
String[] arrayOfString1 = new String[8];
arrayOfString1[0] = "_id";
arrayOfString1[1] = "thread_id";
arrayOfString1[2] = "address";
arrayOfString1[3] = "person";
arrayOfString1[4] = "date";
arrayOfString1[5] = "body";
arrayOfString1[6] = "type";
arrayOfString1[7] = "read";
localCursor = localContentResolver.query(localUri, arrayOfString1, null, null, null);
String[] arrayOfString2 = new String[8];
arrayOfString2[0] = "_id";
arrayOfString2[1] = "thread_id";
arrayOfString2[2] = "address";
arrayOfString2[3] = "person";
arrayOfString2[4] = "date";
arrayOfString2[5] = "body";
arrayOfString2[6] = "type";
arrayOfString2[7] = "read";
localCursor.moveToFirst();
i = localCursor.getCount();
this.pDialog.setMax(i);
this.write.append("<?xml version='1.0' encoding='UTF-8'?>");
this.write.append('\n');
this.write.append("<smsall>");
this.write.append('\n');
while (true) {
localSMSGettersSetters = new SMSGettersSetters();
@SuppressLint("Range") String str2 = localCursor.getString(localCursor.getColumnIndex("_id"));
@SuppressLint("Range") String str3 = localCursor.getString(localCursor.getColumnIndex("thread_id"));
@SuppressLint("Range") String str4 = localCursor.getString(localCursor.getColumnIndex("address"));
@SuppressLint("Range") String str5 = localCursor.getString(localCursor.getColumnIndex("person"));
@SuppressLint("Range") String str6 = localCursor.getString(localCursor.getColumnIndex("date"));
@SuppressLint("Range") String str7 = localCursor.getString(localCursor.getColumnIndex("body")).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll(">", "'").replaceAll("'", "⁄");
@SuppressLint("Range") String str8 = localCursor.getString(localCursor.getColumnIndex("type"));
@SuppressLint("Range") String str9 = localCursor.getString(localCursor.getColumnIndex("read"));
localSMSGettersSetters.setId(str2);
localSMSGettersSetters.setThreadId(str3);
localSMSGettersSetters.setAddres(str4);
localSMSGettersSetters.setPerson(str5);
localSMSGettersSetters.setDate(str6);
localSMSGettersSetters.setBody(str7);
localSMSGettersSetters.setType(str8);
localSMSGettersSetters.setRead(str9);
localSMSGettersSetters.setSentDate(str1);
this.smsBuffer.add(localSMSGettersSetters);
Handler localHandler = new Handler(Looper.getMainLooper());
localHandler.post(new Runnable() {
@Override
public void run() {
final int m = j;
SmsBackupActivity.this.pDialog.setProgress(1 + m);
i++;
int v = -1 + i;
if (m == v) {
Log.d("dismiss", "is called");
SmsBackupActivity.this.pDialog.dismiss();
SmsBackupActivity.this.setBackupDate();
}
i--;
return;
}
});
generateXMLFileForSMS(localSMSGettersSetters);
localCursor.moveToNext();
j++;
if (j == i) {
this.write.append("</smsall>");
this.write.flush();
this.write.close();
pDialog.dismiss();
return;
}
}
}
private void generateXMLFileForSMS(SMSGettersSetters paramSMSGettersSetters) {
try {
this.write.append("<sms>");
this.write.append('\n');
this.write.append("<id>" + paramSMSGettersSetters.getId() + "</id>");
this.write.append('\n');
this.write.append("<threadId>" + paramSMSGettersSetters.getThreadId() + "</threadId>");
this.write.append('\n');
this.write.append("<address>" + paramSMSGettersSetters.getAddress() + "</address>");
this.write.append('\n');
this.write.append("<person>" + paramSMSGettersSetters.getPerson() + "</person>");
this.write.append('\n');
this.write.append("<date>" + paramSMSGettersSetters.getDate() + "</date>");
this.write.append('\n');
this.write.append("<body>" + paramSMSGettersSetters.getBody() + "</body>");
this.write.append('\n');
this.write.append("<type>" + paramSMSGettersSetters.getType() + "</type>");
this.write.append('\n');
this.write.append("<read>" + paramSMSGettersSetters.getRead() + "</read>");
this.write.append('\n');
this.write.append("</sms>");
this.write.append('\n');
return;
} catch (NullPointerException localNullPointerException) {
while (true)
System.out.println("Nullpointer Exception " + localNullPointerException);
} catch (IOException localIOException) {
while (true)
localIOException.printStackTrace();
} catch (Exception localException) {
while (true)
localException.printStackTrace();
}
}
private void launchComponent(String paramString1, String paramString2) {
Intent localIntent = new Intent("android.intent.action.MAIN");
localIntent.addCategory("android.intent.category.LAUNCHER");
localIntent.setComponent(new ComponentName(paramString1, paramString2));
startActivity(localIntent);
}
public void BackupAlert() {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View localView = getLayoutInflater().inflate(R.layout.layout_backup_dialog, null);
final EditText localEditText = (EditText) localView.findViewById(R.id.etFileName);
CharSequence localCharSequence = DateFormat.format("yyMMddhhmmss", new Date().getTime());
localEditText.setText("sms_" + localCharSequence + ".xml");
localBuilder.setView(localView);
localBuilder.setPositiveButton("ok", new OnClickListener() {
@Override
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
SmsBackupActivity.this.xmlfile = localEditText.getText().toString().trim().split(".xml");
SmsBackupActivity.this.setProgressDialog();
new Thread(new Runnable() {
@Override
public void run() {
try {
Looper.prepare();
SmsBackupActivity.this.backupSMS();
Looper.loop();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
});
localBuilder.setNegativeButton("cancel", null);
AlertDialog localAlertDialog = localBuilder.create();
localAlertDialog.getWindow().getAttributes().windowAnimations = R.style.PauseDialogAnimation;
localAlertDialog.show();
}
public String getBackupDate(String paramString) {
return getSharedPreferences("BackupPrefs", 0).getString(paramString, getString(R.string.never_backup));
}
public int getSMSCount() {
Cursor localCursor = getContentResolver().query(Uri.parse("content://sms/"), null, null, null, null);
String[] arrayOfString = localCursor.getColumnNames();
for (int i = 0; ; i++) {
if (i >= arrayOfString.length)
return localCursor.getCount();
Log.d("Names are", arrayOfString[i]);
}
}
public List<FileGetterSetters> getSMSFiles() {
ArrayList localArrayList = new ArrayList();
File[] arrayOfFile = new File(getExternalFilesDir(null) + File.separator + "sms").listFiles();
int i = arrayOfFile.length;
for (int j = 0; ; j++) {
if (j >= i)
return localArrayList;
File localFile = arrayOfFile[j];
FileGetterSetters localFileGetterSetters = new FileGetterSetters();
Log.d("file Name is", localFile.getName());
localFileGetterSetters.setFileName(localFile.getName());
Date localDate = new Date(localFile.lastModified());
Log.d("Modified date is", localDate.toString());
localFileGetterSetters.setDateCreated(localDate.toString());
localArrayList.add(localFileGetterSetters);
}
}
public String getXML(String paramString) {
Log.d("File path is", paramString);
File localFile = new File(paramString);
StringBuilder localStringBuilder = new StringBuilder();
try {
BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(localFile)));
while (true) {
String str = localBufferedReader.readLine();
if (str == null)
return localStringBuilder.toString();
localStringBuilder.append(str);
localStringBuilder.append('\n');
}
} catch (IOException localIOException) {
}
return paramString;
}
public void initAllViews() {
this.btnBackup = ((Button) findViewById(R.id.btnBackup));
this.btnRestore = ((Button) findViewById(R.id.btnRestore));
TextView localTextView1 = (TextView) findViewById(R.id.tvSMS);
this.tvLastBackup = ((TextView) findViewById(R.id.tvLastBackup));
btnBackup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (getSMSCount() > 0) {
SmsBackupActivity.this.BackupAlert();
} else {
Toast.makeText(getApplicationContext(), "SMS not found", Toast.LENGTH_SHORT).show();
}
}
});
btnRestore.setOnClickListener(new View.OnClickListener() {
@SuppressLint("NewApi")
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
RoleManager roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE);
if (roleManager != null && !roleManager.isRoleHeld(ROLE_SMS)) {
SmsReceiver.enable(SmsBackupActivity.this);
Intent intent = roleManager.createRequestRoleIntent(ROLE_SMS);
startActivityForResult(intent, DEF_SMS_REQ);
}
else {
SmsBackupActivity.this.restoreBackupFilesDialog(true);
}
} else {
if (!Telephony.Sms.getDefaultSmsPackage(getApplicationContext()).equals(getPackageName()))
{
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,getPackageName());
startActivityForResult(intent, DEF_SMS_REQ);
}
else
{
SmsBackupActivity.this.restoreBackupFilesDialog(true);
}
}
}
});
localTextView1.setText(Html.fromHtml("<font color='#FFFFFF'>SMS:</font>" + getSMSCount()));
this.tvLastBackup.setText(Html.fromHtml("<font color='#FFFFFF'>" + getString(R.string.last_backup) + ":</font>" + getBackupDate("smsBackupDate")));
}
public void okDialog() {
AlertDialog localAlertDialog = new AlertDialog.Builder(this).create();
localAlertDialog.setMessage(getString(R.string.deleted_successfully_));
localAlertDialog.setButton("ok", new OnClickListener() {
@Override
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
}
});
localAlertDialog.show();
}
@Override
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(R.layout.layout_sms_backupt);
SmsBackupActivity.context = getApplicationContext();
initAllViews();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case DEF_SMS_REQ:
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && isDefaultSmsApp(this) ||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE && resultCode == Activity.RESULT_OK) {
SmsBackupActivity.this.restoreBackupFilesDialog(true);
}
break;
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean isDefaultSmsApp(Context context) {
return context.getPackageName().equals(getDefaultSmsPackage(context));
}
public void openInbox() {
try {
Intent localIntent = new Intent("android.intent.action.MAIN");
localIntent.addCategory("android.intent.category.LAUNCHER");
Iterator localIterator = getPackageManager().queryIntentActivities(localIntent, 0).iterator();
while (localIterator.hasNext()) {
ResolveInfo localResolveInfo = (ResolveInfo) localIterator.next();
if (localResolveInfo.activityInfo.packageName.equalsIgnoreCase("com.android.mms"))
launchComponent(localResolveInfo.activityInfo.packageName, localResolveInfo.activityInfo.name);
}
} catch (ActivityNotFoundException localActivityNotFoundException) {
}
}
@SuppressLint("NewApi")
public void restoreBackup(HashMap<String, String> paramHashMap) {
ContentValues localContentValues = new ContentValues();
localContentValues.put("address", paramHashMap.get("address"));
localContentValues.put("person", paramHashMap.get("person"));
localContentValues.put("date", paramHashMap.get("date"));
localContentValues.put("body", paramHashMap.get("body"));
localContentValues.put("_id", paramHashMap.get("id"));
localContentValues.put("type", paramHashMap.get("type"));
localContentValues.put("read", paramHashMap.get("read"));
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
getContentResolver().insert(Telephony.Sms.CONTENT_URI, localContentValues);
} else {
getContentResolver().insert(Uri.parse("content://sms/"), localContentValues);
}
}catch (Exception e){
}
}
public void restoreBackupFilesDialog(final boolean paramBoolean) {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
localBuilder.setTitle(R.string.backup_files);
ListView localListView = new ListView(this);
final List localList = getSMSFiles();
localListView.setAdapter(new FileAdapter(this, R.layout.item_row_file, localList));
localListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> paramAnonymousAdapterView, View paramAnonymousView, int paramAnonymousInt, long paramAnonymousLong) {
SmsBackupActivity.this.dismiss.dismiss();
if (paramBoolean) {
String str = getExternalFilesDir(null) + File.separator + "sms" + File.separator + ((FileGetterSetters) localList.get(paramAnonymousInt)).getFileName();
Log.d("Seleted file path is", str);
RestoringTask localRestoringTask = new RestoringTask(SmsBackupActivity.this);
String[] arrayOfString = new String[1];
arrayOfString[0] = str;
localRestoringTask.execute(arrayOfString);
}
}
});
localBuilder.setView(localListView);
localBuilder.setNegativeButton("cancel", null);
AlertDialog localAlertDialog = localBuilder.create();
localAlertDialog.getWindow().getAttributes().alpha = 0.6F;
localAlertDialog.getWindow().getAttributes().windowAnimations = R.style.FileDialogAnimation;
this.dismiss = localAlertDialog;
localAlertDialog.show();
}
public void setBackupDate() {
CharSequence localCharSequence = DateFormat.format("yy/MM/dd hh:mm:ss", new Date().getTime());
this.tvLastBackup.setText(Html.fromHtml("<font color='#FFFFFF'>" + getString(R.string.last_backup) + ":</font>" + localCharSequence.toString()));
setLastBackupDate("smsBackupDate", localCharSequence.toString());
}
public void setLastBackupDate(String paramString1, String paramString2) {
SharedPreferences.Editor localEditor = getSharedPreferences("BackupPrefs", 0).edit();
localEditor.putString(paramString1, paramString2);
localEditor.commit();
}
public void setProgressDialog() {
this.pDialog = new ProgressDialog(this);
this.pDialog.setMessage(getString(R.string.backuping_files_please_wait_));
this.pDialog.setIndeterminate(false);
this.pDialog.setProgressDrawable(getResources().getDrawable(R.drawable.greenprogress));
this.pDialog.setMax(100);
this.pDialog.setProgressStyle(1);
this.pDialog.setCancelable(true);
this.pDialog.show();
}
public void viewMessagesDialog() {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
localBuilder.setMessage(getString(R.string.restore_completed_successfully_));
localBuilder.setPositiveButton(getString(R.string.view_messages), new OnClickListener() {
@Override
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
SmsBackupActivity.this.openInbox();
}
});
localBuilder.setNegativeButton("cancel", null);
AlertDialog localAlertDialog = localBuilder.create();
localAlertDialog.getWindow().getAttributes().windowAnimations = R.style.PauseDialogAnimation;
localAlertDialog.show();
}
public class RestoringTask extends AsyncTask<String, Integer, String> {
ProgressDialog pd = new ProgressDialog(SmsBackupActivity.this);
Integer[] arrayOfInteger;
public RestoringTask(SmsBackupActivity smsBackupActivity) {
}
@Override
@SuppressWarnings("unchecked")
protected String doInBackground(String[] paramArrayOfString) {
String str = SmsBackupActivity.this.getXML(paramArrayOfString[0]);
XMLParser localXMLParser = new XMLParser();
NodeList localNodeList = localXMLParser.getDomElement(str).getElementsByTagName("sms");
int i = localNodeList.getLength();
for (int j = 0; ; j++) {
if (j >= i)
return "";
@SuppressWarnings("rawtypes")
HashMap localHashMap = new HashMap();
Element localElement = (Element) localNodeList.item(j);
localHashMap.put("id", localXMLParser.getValue(localElement, "id"));
localHashMap.put("threadId", localXMLParser.getValue(localElement, "threadId"));
localHashMap.put("address", localXMLParser.getValue(localElement, "address"));
localHashMap.put("person", localXMLParser.getValue(localElement, "person"));
localHashMap.put("date", localXMLParser.getValue(localElement, "date"));
localHashMap.put("body", localXMLParser.getValue(localElement, "body"));
localHashMap.put("type", localXMLParser.getValue(localElement, "type"));
localHashMap.put("read", localXMLParser.getValue(localElement, "read"));
SmsBackupActivity.this.restoreBackup(localHashMap);
Integer[] arrayOfInteger = new Integer[2];
arrayOfInteger[0] = Integer.valueOf(i);
arrayOfInteger[1] = Integer.valueOf(j);
publishProgress(arrayOfInteger);
}
}
@Override
@SuppressLint("InlinedApi")
protected void onPostExecute(String paramString) {
super.onPostExecute(paramString);
((TextView) SmsBackupActivity.this.findViewById(R.id.tvSMS)).setText(Html.fromHtml("<font color='#FFFFFF'>SMS:</font>" + SmsBackupActivity.this.getSMSCount()));
this.pd.dismiss();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Toast.makeText(getApplicationContext(), "Restored successfully", Toast.LENGTH_SHORT).show();
} else {
SmsBackupActivity.this.viewMessagesDialog();
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
this.pd.setProgressStyle(1);
this.pd.setMessage(SmsBackupActivity.this.getString(R.string.restoring_backups_));
this.pd.setProgressDrawable(SmsBackupActivity.this.getResources().getDrawable(R.drawable.greenprogress));
this.pd.show();
}
@Override
protected void onProgressUpdate(Integer[] paramArrayOfInteger) {
this.pd.setMax(paramArrayOfInteger[0].intValue());
this.pd.setProgress(paramArrayOfInteger[1].intValue());
super.onProgressUpdate(paramArrayOfInteger);
}
}
}
Also, in my MainActivity file, I've taken Manifest.permission.READ_SMS permission.
Update: I deleted all the text messages from the phone and there is no similar id and the error Logcat is no longer shown but The bug still remains and SMS messages cannot be restored only on Xiaomi phones.
I just noticed that the issue with duplicated IDs has been resolved. Well, the issue only persists on Xiaomi phones.
Try to check the following possibilities.
If the issue persists, consider alternative methods for SMS backup and restore on Xiaomi devices. Xiaomi's customizations may conflict with certain approaches. You could explore options like using Xiaomi's official backup and restore APIs if available.