Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abedbf07 authored by Sahin Caliskan's avatar Sahin Caliskan Committed by Gerrit Code Review
Browse files

Merge "Implement RcsThread querying (opt)"

parents 32d93e0e 413d24de
Loading
Loading
Loading
Loading
+134 −0
Original line number Diff line number Diff line
@@ -14,31 +14,44 @@
 * limitations under the License.
 */

package com.android.internal.telephony;
package com.android.internal.telephony.ims;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.ServiceManager;
import android.telephony.Rlog;
import android.telephony.ims.Rcs1To1Thread;
import android.telephony.ims.RcsMessageStore;
import android.telephony.ims.RcsParticipant;
import android.telephony.ims.RcsThread;
import android.telephony.ims.RcsThreadQueryContinuationToken;
import android.telephony.ims.RcsThreadQueryParameters;
import android.telephony.ims.RcsThreadQueryResult;
import android.telephony.ims.aidl.IRcs;

import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;


/** Backing implementation of {@link RcsMessageStore}. */
public class RcsMessageStoreController extends IRcs.Stub {
    public static final String PARTICIPANT_ADDRESS_KEY = "participant_address";
    private static final String TAG = "RcsMessageStoreController";
    private static final String RCS_SERVICE_NAME = "ircs";

    private static RcsMessageStoreController sInstance;

    private final Context mContext;
    private final ContentResolver mContentResolver;

    /** Initialize the instance. Should only be called once. */
    public static RcsMessageStoreController init(Context context) {
        synchronized (RcsMessageStoreController.class) {
            if (sInstance == null) {
                sInstance = new RcsMessageStoreController(context);
                sInstance = new RcsMessageStoreController(context.getContentResolver());
            } else {
                Rlog.e(TAG, "init() called multiple times! sInstance = " + sInstance);
            }
@@ -46,16 +59,16 @@ public class RcsMessageStoreController extends IRcs.Stub {
        return sInstance;
    }

    private RcsMessageStoreController(Context context) {
        mContext = context;
    private RcsMessageStoreController(ContentResolver contentResolver) {
        mContentResolver = contentResolver;
        if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
            ServiceManager.addService(RCS_SERVICE_NAME, this);
        }
    }

    @VisibleForTesting
    public RcsMessageStoreController(Context context, Void unused) {
        mContext = context;
    public RcsMessageStoreController(ContentResolver contentResolver, Void unused) {
        mContentResolver = contentResolver;
    }

    @Override
@@ -68,4 +81,54 @@ public class RcsMessageStoreController extends IRcs.Stub {
        // TODO - add implementation. Return a magic number for now to test the RPC calls
        return 1018;
    }

    @Override
    public RcsThreadQueryResult getRcsThreads(RcsThreadQueryParameters queryParameters) {
        // TODO - refine implementation to include tokens for the next query
        Cursor rcsThreadsCursor = mContentResolver.query(
                RcsThreadQueryHelper.THREADS_URI,
                RcsThreadQueryHelper.THREAD_PROJECTION,
                RcsThreadQueryHelper.buildWhereClause(queryParameters),
                null,
                queryParameters.isAscending()
                        ? RcsThreadQueryHelper.ASCENDING : RcsThreadQueryHelper.DESCENDING);

        List<RcsThread> rcsThreadList = new ArrayList<>();

        // TODO - currently this only creates 1 to 1 threads - fix this
        while (rcsThreadsCursor != null && rcsThreadsCursor.moveToNext()) {
            Rcs1To1Thread rcs1To1Thread = new Rcs1To1Thread(rcsThreadsCursor.getInt(0));
            rcsThreadList.add(rcs1To1Thread);
        }

        return new RcsThreadQueryResult(null, rcsThreadList);
    }

    @Override
    public RcsThreadQueryResult getRcsThreadsWithToken(
            RcsThreadQueryContinuationToken continuationToken) {
        // TODO - implement
        return null;
    }

    @Override
    public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
        // TODO - use recipient to add a thread

        ContentValues contentValues = new ContentValues(0);
        mContentResolver.insert(RcsThreadQueryHelper.THREADS_URI, contentValues);

        return null;
    }

    @Override
    public RcsParticipant createRcsParticipant(String canonicalAddress) {
        // TODO - refine implementation to disallow duplicate participants
        ContentValues contentValues = new ContentValues();
        contentValues.put(PARTICIPANT_ADDRESS_KEY, canonicalAddress);
        mContentResolver.insert(RcsThreadQueryHelper.PARTICIPANTS_URI, contentValues);

        // TODO - return the newly created participant
        return null;
    }
}
+38 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 * Copyright (C) 2017 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.
@@ -13,31 +13,26 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.telephony.ims;

package com.android.internal.telephony.rcs;

import static org.junit.Assert.assertEquals;

import com.android.internal.telephony.RcsMessageStoreController;
import com.android.internal.telephony.TelephonyTest;

import org.junit.Before;
import org.junit.Test;

public class RcsMessageStoreControllerTest extends TelephonyTest {

    private RcsMessageStoreController mRcsMessageStoreController;

    @Before
    public void setUp() {
        mRcsMessageStoreController = new RcsMessageStoreController(mContext, null);
    }
import android.net.Uri;
import android.telephony.ims.RcsThreadQueryParameters;

/**
     * TODO(sahinc): fix the test once there is an implementation in place
 * A helper class focused on querying RCS threads from the
 * {@link com.android.providers.telephony.RcsProvider}
 */
    @Test
    public void testGetMessageCount() {
        assertEquals(1018, mRcsMessageStoreController.getMessageCount(0));
class RcsThreadQueryHelper {
    static final String ASCENDING = "ASCENDING";
    static final String DESCENDING = "DESCENDING";
    static final String THREAD_ID = "_id";

    static final Uri THREADS_URI = Uri.parse("content://rcs/thread");
    static final Uri PARTICIPANTS_URI = Uri.parse("content://rcs/participant");
    static final String[] THREAD_PROJECTION = new String[]{THREAD_ID};

    static String buildWhereClause(RcsThreadQueryParameters queryParameters) {
        // TODO - implement
        return null;
    }
}
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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 com.android.internal.telephony.ims;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;

import android.database.Cursor;
import android.net.Uri;
import android.telephony.ims.RcsParticipant;
import android.telephony.ims.RcsThreadQueryParameters;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;

import com.android.internal.telephony.TelephonyTest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class RcsMessageStoreControllerTest extends TelephonyTest {

    private RcsMessageStoreController mRcsMessageStoreController;
    private MockContentResolver mContentResolver;
    private FakeRcsProvider mFakeRcsProvider;

    @Mock
    RcsParticipant mMockParticipant;

    @Before
    public void setUp() throws Exception {
        super.setUp("RcsMessageStoreControllerTest");
        MockitoAnnotations.initMocks(this);

        mFakeRcsProvider = new FakeRcsProvider();
        mContentResolver = (MockContentResolver) mContext.getContentResolver();
        mContentResolver.addProvider("rcs", mFakeRcsProvider);

        mRcsMessageStoreController = new RcsMessageStoreController(mContentResolver, null);
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    public void testGetRcsThreads() {
        doReturn(123).when(mMockParticipant).getId();
        RcsThreadQueryParameters queryParameters =
                RcsThreadQueryParameters.builder().withParticipant(mMockParticipant).isGroupThread(
                        true).limitResultsTo(30).sort(true).build();

        mFakeRcsProvider.setExpectedQueryParameters(Uri.parse("content://rcs/thread"),
                new String[]{"_id"}, null, null, "ASCENDING");
        mRcsMessageStoreController.getRcsThreads(queryParameters);
    }

    /**
     * TODO(sahinc): fix the test once there is an implementation in place
     */
    @Test
    public void testGetMessageCount() {
        assertEquals(1018, mRcsMessageStoreController.getMessageCount(0));
    }

    /**
     * Mocking/spying ContentProviders break in different ways. Use a fake instead. The
     * RcsMessageStoreController doesn't care if RcsProvider works as expected (and doesn't have
     * visibility into it) - so verifying whether we use the correct parameters should suffice.
     */
    class FakeRcsProvider extends MockContentProvider {
        private Uri mExpectedUri;
        private String[] mExpectedProjection;
        private String mExpectedWhereClause;
        private String[] mExpectedWhereArgs;
        private String mExpectedSortOrder;

        void setExpectedQueryParameters(Uri uri, String[] projection, String whereClause,
                String[] whereArgs, String sortOrder) {
            mExpectedUri = uri;
            mExpectedProjection = projection;
            mExpectedWhereClause = whereClause;
            mExpectedWhereArgs = whereArgs;
            mExpectedSortOrder = sortOrder;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String whereClause, String[] whereArgs,
                String sortOrder) {
            assertThat(uri).isEqualTo(mExpectedUri);
            assertThat(projection).isEqualTo(mExpectedProjection);
            assertThat(whereClause).isEqualTo(mExpectedWhereClause);
            assertThat(whereArgs).isEqualTo(mExpectedWhereArgs);
            assertThat(sortOrder).isEqualTo(mExpectedSortOrder);
            return null;
        }

    }
}