/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package android.provider.cts;

import com.google.android.mms.ContentType;
import com.google.android.mms.pdu.CharacterSets;

import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.Telephony;
import android.util.Log;

/**
 * CTS tests for backup and restore of blocked numbers using local transport.
 */
// To run the tests in this file w/o running all the cts tests:
// make cts
// cts-tradefed
// run cts -m CtsProviderTestCases --test android.provider.cts.SmsBackupRestoreTest
public class SmsBackupRestoreTest extends TestCaseThatRunsIfTelephonyIsEnabled {
    private static final String TAG = "SmsBackupRestoreTest";
    private static final String LOCAL_BACKUP_COMPONENT =
            "com.android.localtransport/.LocalTransport";
    private static final String TELEPHONY_PROVIDER_PACKAGE = "com.android.providers.telephony";

    private static final String[] smsAddressBody1 = new String[] {"+123" , "sms CTS text"};
    private static final String[] smsAddressBody2 = new String[] {"+456" , "sms CTS text 2"};
    private static final String[] mmsAddresses = new String[] {"+1223", "+43234234"};
    private static final String mmsSubject = "MMS Subject CTS";
    private static final String mmsBody = "MMS body CTS";

    private static final String[] ID_PROJECTION = new String[] { BaseColumns._ID };
    private static final String[] ID_TEXT_ONLY_PROJECTION = new String[] { BaseColumns._ID,
            Telephony.Mms.TEXT_ONLY };
    private static final String SMS_SELECTION = Telephony.Sms.ADDRESS + " = ? and "
            + Telephony.Sms.BODY + " = ?";

    private static final String MMS_SELECTION = Telephony.Mms.SUBJECT + " = ?";

    private static final String[] MMS_PART_TEXT_PROJECTION = new String[]{Telephony.Mms.Part.TEXT};
    private static final String MMS_PART_SELECTION = Telephony.Mms.Part.MSG_ID + " = ?";
    private static final String MMS_PART_TEXT_SELECTION = Telephony.Mms.Part.CONTENT_TYPE + " = ?";
    private static final String[] MMS_ADDR_PROJECTION = new String[] { Telephony.Mms.Addr.ADDRESS };
    private static final String MMS_ADDR_SELECTION = Telephony.Mms.Addr.MSG_ID + " = ?";

    private Context mContext;
    private ContentResolver mContentResolver;
    private UiAutomation mUiAutomation;
    private String mOldTransport;
    private boolean mOldBackupEnabled;
    private boolean mHasFeature;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        // Wait for the UI Thread to become idle.
        getInstrumentation().waitForIdleSync();
        mContext = getInstrumentation().getContext();
        mContentResolver = mContext.getContentResolver();
        mUiAutomation = getInstrumentation().getUiAutomation();
        mHasFeature = isFeatureSupported();
        if (mHasFeature) {
            ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
            mOldTransport =
                    ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
            mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation);
            clearMessages();
            wipeBackup();
        }
    }

    @Override
    protected void tearDown() throws Exception {
        if (mHasFeature) {
            wipeBackup();
            clearMessages();
            ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation);
            ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
            ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
        }

        super.tearDown();
    }

    private boolean isFeatureSupported() throws Exception {
        return (ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)
                && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
    }

    private void clearMessages() {
        mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1);
        mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2);
        try (Cursor mmsCursor =
                     mContentResolver.query(Telephony.Mms.CONTENT_URI, ID_PROJECTION, MMS_SELECTION,
                             new String[] {mmsSubject}, null)) {
            if (mmsCursor != null && mmsCursor.moveToFirst()) {
                final long mmsId = mmsCursor.getLong(0);
                final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon()
                        .appendPath(String.valueOf(mmsId)).appendPath("part").build();
                mContentResolver.delete(partUri, MMS_PART_SELECTION,
                        new String[]{String.valueOf(mmsId)});

                final Uri addrUri = getMmsAddrUri(mmsId);
                mContentResolver.delete(addrUri, MMS_ADDR_SELECTION,
                        new String[]{String.valueOf(mmsId)});
            }
        }
        mContentResolver.delete(Telephony.Mms.CONTENT_URI, MMS_SELECTION, new String[]{mmsSubject});
    }

    /**
     * Test adds 2 SMS messages, 1 text-only MMS messages and 1 non-text-only, runs backup,
     * deletes the messages from the provider, runs restore, check if the messages are in the
     * provider (with non-text-only one).
     * @throws Exception
     */
    public void testSmsBackupRestore() throws Exception {
        if (!mHasFeature) {
            Log.i(TAG, "skipping testSmsBackupRestore");
            return;
        }

        ContentValues smsContentValues[] = new ContentValues[] {
                createSmsValues(smsAddressBody1),
                createSmsValues(smsAddressBody2)};
        Log.i(TAG, "Put 2 SMS into the provider");
        mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, smsContentValues);

        Log.i(TAG, "Put 1 text MMS into the provider");
        addMms(true /*isTextOnly*/, mmsBody, mmsSubject, mmsAddresses);
        Log.i(TAG, "Put 1 non-text MMS into the provider");
        addMms(false /*isTextOnly*/, mmsBody, mmsSubject, mmsAddresses);

        Log.i(TAG, "Run backup");
        ProviderTestUtils.runBackup(TELEPHONY_PROVIDER_PACKAGE, mUiAutomation);
        Log.i(TAG, "Delete the messages from the provider");
        clearMessages();
        Log.i(TAG, "Run restore");
        ProviderTestUtils.runRestore(TELEPHONY_PROVIDER_PACKAGE, mUiAutomation);

        Log.i(TAG, "Check the providers for the messages");
        assertEquals(1,
                mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1));
        assertEquals(1,
                mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2));

        try (Cursor mmsCursor = mContentResolver.query(Telephony.Mms.CONTENT_URI,
              ID_TEXT_ONLY_PROJECTION, MMS_SELECTION, new String[] {mmsSubject}, null)) {
            assertNotNull(mmsCursor);
            assertEquals(2, mmsCursor.getCount());
            for (mmsCursor.moveToFirst(); !mmsCursor.isAfterLast(); mmsCursor.moveToNext()) {
              final long mmsId = mmsCursor.getLong(0);
              final long mmsTextOnly = mmsCursor.getLong(1);
              assertEquals(mmsTextOnly, 1);
              final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon()
                  .appendPath(String.valueOf(mmsId)).appendPath("part").build();
              // Check the body.
              try (Cursor partCursor = mContentResolver.query(partUri, MMS_PART_TEXT_PROJECTION,
                    MMS_PART_TEXT_SELECTION, new String[]{ ContentType.TEXT_PLAIN }, null)) {
                assertNotNull(partCursor);
                assertEquals(1, partCursor.getCount());
                assertTrue(partCursor.moveToFirst());
                assertTrue(partCursor.getString(0).startsWith(mmsBody));
              }

              // Check if there are 2 parts (smil and body).
              assertEquals(2, mContentResolver.delete(partUri, MMS_PART_SELECTION,
                    new String[]{String.valueOf(mmsId)}));

              // Check addresses.
              final Uri addrUri = getMmsAddrUri(mmsId);
              try (Cursor addrCursor = mContentResolver.query(addrUri, MMS_ADDR_PROJECTION,
                    MMS_ADDR_SELECTION, new String[]{String.valueOf(mmsId)}, null)) {
                assertNotNull(addrCursor);
                for (String addr : mmsAddresses) {
                  addrCursor.moveToNext();
                  assertEquals(addr, addrCursor.getString(0));
                }
              }
              assertEquals(mmsAddresses.length, mContentResolver.delete(addrUri, MMS_ADDR_SELECTION,
                    new String[]{String.valueOf(mmsId)}));
            }
        }
    }

    private static Uri getMmsAddrUri(long mmsId) {
        Uri.Builder builder = Telephony.Mms.CONTENT_URI.buildUpon();
        builder.appendPath(String.valueOf(mmsId)).appendPath("addr");
        return builder.build();
    }

    private void addMms(boolean isTextOnly, String body, String subject, String[] addresses) {
        // Insert mms.
        final ContentValues mmsValues = new ContentValues(2);
        mmsValues.put(Telephony.Mms.TEXT_ONLY, isTextOnly ? 1 : 0);
        mmsValues.put(Telephony.Mms.MESSAGE_TYPE, 128);
        mmsValues.put(Telephony.Mms.SUBJECT, subject);
        final Uri mmsUri = mContentResolver.insert(Telephony.Mms.CONTENT_URI, mmsValues);
        assertNotNull(mmsUri);
        final long mmsId = ContentUris.parseId(mmsUri);

        final String srcName = String.format("text.%06d.txt", 0);
        // Insert body part.
        final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon()
                .appendPath(String.valueOf(mmsId)).appendPath("part").build();

        final ContentValues values = new ContentValues(8);
        values.put(Telephony.Mms.Part.MSG_ID, mmsId);
        values.put(Telephony.Mms.Part.SEQ, 0);
        values.put(Telephony.Mms.Part.CONTENT_TYPE, ContentType.TEXT_PLAIN);
        values.put(Telephony.Mms.Part.NAME, srcName);
        values.put(Telephony.Mms.Part.CONTENT_ID, "<"+srcName+">");
        values.put(Telephony.Mms.Part.CONTENT_LOCATION, srcName);
        values.put(Telephony.Mms.Part.CHARSET, CharacterSets.DEFAULT_CHARSET);
        if (!isTextOnly) {
            body = body + " Non text-only";
        }
        values.put(Telephony.Mms.Part.TEXT, body);
        mContentResolver.insert(partUri, values);

        // Insert addresses.
        final Uri addrUri = Uri.withAppendedPath(mmsUri, "addr");
        for (int i = 0; i < addresses.length; ++i) {
            ContentValues addrValues = new ContentValues(3);
            addrValues.put(Telephony.Mms.Addr.TYPE, i);
            addrValues.put(Telephony.Mms.Addr.CHARSET, CharacterSets.DEFAULT_CHARSET);
            addrValues.put(Telephony.Mms.Addr.ADDRESS, addresses[i]);
            addrValues.put(Telephony.Mms.Addr.MSG_ID, mmsId);
            mContentResolver.insert(addrUri, addrValues);
        }
    }

    private static ContentValues createSmsValues(String[] addressBody) {
        ContentValues smsRow = new ContentValues();
        smsRow.put(Telephony.Sms.ADDRESS, addressBody[0]);
        smsRow.put(Telephony.Sms.BODY, addressBody[1]);
        return smsRow;
    }

    private void wipeBackup() throws Exception {
        ProviderTestUtils.wipeBackup(LOCAL_BACKUP_COMPONENT, TELEPHONY_PROVIDER_PACKAGE,
                mUiAutomation);
    }
}
