Backup sms in Google Drive

In previous post I described how to make simple actions with Google Drive from own apps.

In this post I will try to do a simple sms backup in a google drive folder, and I will use the new app data folder.

It is a quite simple operation.If you've already understood how to use Google Drive, the only difficulty is to find a way to retrieve sms from your device.
There are many implementations on the web, but there are not public API.
I choose to use TelephonyProviderConstants that you can find in the awesome DashClock app.

First of all we have to do these steps described in previous post:
  • Enable the Drive API from Google API Console
  • Add Drive API v2 to your project
  • Make sure the Google Play Services client library is being included in the Android's project build path

Then,in order to backup sms, in our app we can do these steps:
We can do a simple query to retrieve sms from device:
/**
 * Retrieve sms
 * 
 * @return
 */
private Cursor getSmsInboxCursor() {

   try {
      return getContentResolver().query(
         TelephonyProviderConstants.Sms.CONTENT_URI,
         SmsQuery.PROJECTION, SmsQuery.WHERE_INBOX, null,
         TelephonyProviderConstants.Sms.DEFAULT_SORT_ORDER);
   } catch (Exception e) {
      Log.e(TAG, "Error accessing conversations cursor in SMS/MMS provider",e);
      return null;
   }
}
Then we can iterate with a Cursor, and build a text for our backup.
We can easily make a csv, txt or xml file.
In our example we will concatenate field in a txt file:
private StringBuilder readSmsInbox() {
   Cursor cursor = getSmsInboxCursor();
   StringBuilder messages = new StringBuilder();
   String and = "";

   if (cursor != null) {
     final String[] columns = cursor.getColumnNames();
     while (cursor.moveToNext()) {
        messages.append(and);
        long contactId = cursor.getLong(SmsQuery.PERSON);
        String address = cursor.getString(SmsQuery.ADDRESS);
 
        final Map msgMap = new HashMap,columns.length);
        for (int i = 0; i < columns.length; i++) {
            String value = cursor.getString(i);
            msgMap.put(columns[i], cursor.getString(i));
            messages.append(columns[i]);
            messages.append("=");
            messages.append(value);
            messages.append(";");
        }
        and = "\n";

        String displayName = address;

        if (contactId > 0) {
            // Retrieve from Contacts with contact id
            Cursor contactCursor = tryOpenContactsCursorById(contactId);
            if (contactCursor != null) {
               if (contactCursor.moveToFirst()) {
                  displayName = contactCursor.getString(RawContactsQuery.DISPLAY_NAME);
               } else {
                  contactId = 0;
               }
               contactCursor.close();
            }
        } else {
            if (contactId <= 0) {
               // Retrieve with address
               Cursor contactCursor = tryOpenContactsCursorByAddress(address);
               if (contactCursor != null) {
                  if (contactCursor.moveToFirst()) {
                      displayName = contactCursor
                                      .getString(ContactsQuery.DISPLAY_NAME);
                  }
                  contactCursor.close();
               }
            }
        }

        messages.append("displayName");
        messages.append("=");
        messages.append(displayName);
        messages.append(";");
     }
   }
   return messages;
}
In this code, we also retrive the display name with ContactsQuery.
We can use this code to save in Google Drive:
/**
 * Backup SMSs to GDrive
 */
private void backupSmsToGDrive() {
  
   // Check for use data folder
   CheckBox checkbox=(CheckBox)findViewById(R.id.appdatafolder);
   if (checkbox!=null && checkbox.isChecked())
      useDataFolder=true;
   else
      useDataFolder=false;
  
  
   Thread t = new Thread(new Runnable() {
       @Override
       public void run() {
           try {

               showToast("Start process");
     
               // Retrieve sms
               StringBuilder messages = readSmsInbox();
               Log.i(TAG, messages.toString());

               // Create sms backup Folder 
               File folder=null;
               if (mService == null)
                   initService();
     
               if (!useDataFolder)
                   folder= createBackupFolder();

               // File's metadata.
               String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                    Locale.ITALIAN).format(new Date());
    
               File body = new File();
               body.setTitle("Sms Backup " + timeStamp);
               body.setMimeType("text/plain");
               body.setDescription("Backup sms");

               // Set the parent folder.
               if (useDataFolder)
                    body.setParents(Arrays.asList(new ParentReference().setId("appdata")));
               else
                    body.setParents(Arrays.asList(new ParentReference()
                              .setId(folder.getId())));

               ByteArrayContent content = ByteArrayContent.fromString(
                              "text/plain", messages.toString());
               File file = mService.files().insert(body, content).execute();
     
               if (file != null) {
                   showToast("Sms backup uploaded: " + file.getTitle());
               }

        } catch (UserRecoverableAuthIOException e) {
            Intent intent = e.getIntent();
            startActivityForResult(intent, REQUEST_AUTHORIZATION_FOLDER);
        } catch (IOException e) {
            Log.e("TAG", "Error in backup", e);
        }
}

This example works with a simple folder, and also works with the new Application Data Folder.
It is very simple to use this special folder. You have to use this simple code to set this folder.
  body.setParents(Arrays.asList(new ParentReference().setId("appdata")));
Pay attention with authorization.
To be able to use your Application Data folder, request access to the following scope:

https://www.googleapis.com/auth/drive.appdata

We can modify our code, and use it to add this scope:
   mCredential = GoogleAccountCredential.usingOAuth2(this,
        DriveScopes.DRIVE,"https://www.googleapis.com/auth/drive.appdata");

The 'Application Data folder' is a special folder that is only accessible by your application. Its content is hidden from the user, and from other apps.

You can get code from GitHub:

Comments

Post a Comment

Popular posts from this blog

AntiPattern: freezing a UI with Broadcast Receiver

How to centralize the support libraries dependencies in gradle

NotificationListenerService and kitkat