Merge "Implement RcsThread querying (base)"

This commit is contained in:
Sahin Caliskan
2019-01-05 21:19:09 +00:00
committed by Gerrit Code Review
15 changed files with 642 additions and 9 deletions

View File

@@ -23,6 +23,10 @@ import android.os.Parcel;
* @hide - TODO(sahinc) make this public
*/
public class Rcs1To1Thread extends RcsThread {
public Rcs1To1Thread(int threadId) {
super(threadId);
}
public static final Creator<Rcs1To1Thread> CREATOR = new Creator<Rcs1To1Thread>() {
@Override
public Rcs1To1Thread createFromParcel(Parcel in) {
@@ -36,6 +40,7 @@ public class Rcs1To1Thread extends RcsThread {
};
protected Rcs1To1Thread(Parcel in) {
super(in);
}
@Override
@@ -45,5 +50,7 @@ public class Rcs1To1Thread extends RcsThread {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(RCS_1_TO_1_TYPE);
super.writeToParcel(dest, flags);
}
}

View File

@@ -36,6 +36,7 @@ public class RcsGroupThread extends RcsThread {
};
protected RcsGroupThread(Parcel in) {
super(in);
}
@Override
@@ -45,5 +46,7 @@ public class RcsGroupThread extends RcsThread {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(RCS_GROUP_TYPE);
super.writeToParcel(dest, flags);
}
}

View File

@@ -16,6 +16,8 @@
package android.telephony.ims;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
@@ -27,26 +29,93 @@ import android.telephony.ims.aidl.IRcs;
* @hide - TODO make this public
*/
public class RcsMessageStore {
private static final String TAG = "RcsMessageStore";
private static final boolean VDBG = false;
static final String TAG = "RcsMessageStore";
/**
* Delete the RcsThread identified by the given threadId.
* Returns the first chunk of existing {@link RcsThread}s in the common storage.
* @param queryParameters Parameters to specify to return a subset of all RcsThreads.
* Passing a value of null will return all threads.
*/
@WorkerThread
public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParameters queryParameters) {
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
return iRcs.getRcsThreads(queryParameters);
}
} catch (RemoteException re) {
Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
}
return null;
}
/**
* Returns the next chunk of {@link RcsThread}s in the common storage.
* @param continuationToken A token to continue the query to get the next chunk. This is
* obtained through {@link RcsThreadQueryResult#nextChunkToken}.
*/
@WorkerThread
public RcsThreadQueryResult getRcsThreads(RcsThreadQueryContinuationToken continuationToken) {
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
return iRcs.getRcsThreadsWithToken(continuationToken);
}
} catch (RemoteException re) {
Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
}
return null;
}
/**
* Creates a new 1 to 1 thread with the given participant and persists it in the storage.
*/
@WorkerThread
public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
return iRcs.createRcs1To1Thread(recipient);
}
} catch (RemoteException re) {
Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcs1To1Thread", re);
}
return null;
}
/**
* Delete the {@link RcsThread} identified by the given threadId.
* @param threadId threadId of the thread to be deleted.
*/
@WorkerThread
public void deleteThread(int threadId) {
if (VDBG) logd("deleteThread: threadId: " + threadId);
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
iRcs.deleteThread(threadId);
}
} catch (RemoteException re) {
Rlog.e(TAG, "RcsMessageStore: Exception happened during deleteThread", re);
}
}
private static void logd(String msg) {
Rlog.d(TAG, msg);
/**
* Creates a new participant and persists it in the storage.
* @param canonicalAddress The defining address (e.g. phone number) of the participant.
*/
public RcsParticipant createRcsParticipant(String canonicalAddress) {
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
return iRcs.createRcsParticipant(canonicalAddress);
}
} catch (RemoteException re) {
Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcsParticipant", re);
}
return null;
}
}

View File

@@ -23,6 +23,16 @@ import android.os.Parcelable;
* @hide - TODO(sahinc) make this public
*/
public class RcsParticipant implements Parcelable {
/**
* Returns the row id of this participant.
*
* TODO(sahinc) implement
* @hide
*/
public int getId() {
return 12345;
}
public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() {
@Override
public RcsParticipant createFromParcel(Parcel in) {

View File

@@ -16,7 +16,9 @@
package android.telephony.ims;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
/**
* RcsThread represents a single RCS conversation thread. It holds messages that were sent and
@@ -24,5 +26,50 @@ import android.os.Parcelable;
* @hide - TODO(sahinc) make this public
*/
public abstract class RcsThread implements Parcelable {
// Since this is an abstract class that gets parcelled, the sub-classes need to write these
// magic values into the parcel so that we know which type to unparcel into.
protected static final int RCS_1_TO_1_TYPE = 998;
protected static final int RCS_GROUP_TYPE = 999;
protected int mThreadId;
protected RcsThread(int threadId) {
mThreadId = threadId;
}
protected RcsThread(Parcel in) {
mThreadId = in.readInt();
}
public static final Creator<RcsThread> CREATOR = new Creator<RcsThread>() {
@Override
public RcsThread createFromParcel(Parcel in) {
int type = in.readInt();
switch (type) {
case RCS_1_TO_1_TYPE:
return new Rcs1To1Thread(in);
case RCS_GROUP_TYPE:
return new RcsGroupThread(in);
default:
Log.e(RcsMessageStore.TAG, "Cannot unparcel RcsThread, wrong type: " + type);
}
return null;
}
@Override
public RcsThread[] newArray(int size) {
return new RcsThread[0];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mThreadId);
}
}

View File

@@ -0,0 +1,20 @@
/*
**
** 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 android.telephony.ims;
parcelable RcsThreadQueryContinuationToken;

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 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 android.telephony.ims;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A continuation token to provide for {@link RcsMessageStore#getRcsThreads}. Use this token to
* break large queries into manageable chunks
* @hide - TODO make this public
*/
public class RcsThreadQueryContinuationToken implements Parcelable {
protected RcsThreadQueryContinuationToken(Parcel in) {
}
public static final Creator<RcsThreadQueryContinuationToken> CREATOR =
new Creator<RcsThreadQueryContinuationToken>() {
@Override
public RcsThreadQueryContinuationToken createFromParcel(Parcel in) {
return new RcsThreadQueryContinuationToken(in);
}
@Override
public RcsThreadQueryContinuationToken[] newArray(int size) {
return new RcsThreadQueryContinuationToken[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
}

View File

@@ -0,0 +1,20 @@
/*
**
** 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 android.telephony.ims;
parcelable RcsThreadQueryParameters;

View File

@@ -0,0 +1,225 @@
/*
* Copyright (C) 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 android.telephony.ims;
import android.annotation.CheckResult;
import android.os.Parcel;
import android.os.Parcelable;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)} in
* order to select a subset of {@link RcsThread}s present in the message store.
* @hide TODO - make the Builder and builder() public. The rest should stay internal only.
*/
public class RcsThreadQueryParameters implements Parcelable {
private final boolean mIsGroup;
private final Set<RcsParticipant> mRcsParticipants;
private final int mLimit;
private final boolean mIsAscending;
RcsThreadQueryParameters(boolean isGroup, Set<RcsParticipant> participants, int limit,
boolean isAscending) {
mIsGroup = isGroup;
mRcsParticipants = participants;
mLimit = limit;
mIsAscending = isAscending;
}
/**
* Returns a new builder to build a query with.
* TODO - make public
*/
public static Builder builder() {
return new Builder();
}
/**
* This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
* the list of participants.
* @hide
*/
public Set<RcsParticipant> getRcsParticipants() {
return mRcsParticipants;
}
/**
* This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
* whether group threads should be queried
* @hide
*/
public boolean isGroupThread() {
return mIsGroup;
}
/**
* This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
* the number of tuples the result query should be limited to.
*/
public int getLimit() {
return mLimit;
}
/**
* This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
* determine the sort order.
*/
public boolean isAscending() {
return mIsAscending;
}
/**
* A helper class to build the {@link RcsThreadQueryParameters}.
*/
public static class Builder {
private boolean mIsGroupThread;
private Set<RcsParticipant> mParticipants;
private int mLimit = 100;
private boolean mIsAscending;
/**
* Package private constructor for {@link RcsThreadQueryParameters.Builder}. To obtain this,
* {@link RcsThreadQueryParameters#builder()} needs to be called.
*/
Builder() {
mParticipants = new HashSet<>();
}
/**
* Limits the query to only return group threads.
* @param isGroupThread Whether to limit the query result to group threads.
* @return The same instance of the builder to chain parameters.
*/
@CheckResult
public Builder isGroupThread(boolean isGroupThread) {
mIsGroupThread = isGroupThread;
return this;
}
/**
* Limits the query to only return threads that contain the given participant.
* @param participant The participant that must be included in all of the returned threads.
* @return The same instance of the builder to chain parameters.
*/
@CheckResult
public Builder withParticipant(RcsParticipant participant) {
mParticipants.add(participant);
return this;
}
/**
* Limits the query to only return threads that contain the given list of participants.
* @param participants An iterable list of participants that must be included in all of the
* returned threads.
* @return The same instance of the builder to chain parameters.
*/
@CheckResult
public Builder withParticipants(Iterable<RcsParticipant> participants) {
for (RcsParticipant participant : participants) {
mParticipants.add(participant);
}
return this;
}
/**
* Desired number of threads to be returned from the query. Passing in 0 will return all
* existing threads at once. The limit defaults to 100.
* @param limit The number to limit the query result to.
* @return The same instance of the builder to chain parameters.
* @throws InvalidParameterException If the given limit is negative.
*/
@CheckResult
public Builder limitResultsTo(int limit) throws InvalidParameterException {
if (limit < 0) {
throw new InvalidParameterException("The query limit must be non-negative");
}
mLimit = limit;
return this;
}
/**
* Sorts the results returned from the query via thread IDs.
*
* TODO - add sorting support for other fields
*
* @param isAscending whether to sort in ascending order or not
* @return The same instance of the builder to chain parameters.
*/
@CheckResult
public Builder sort(boolean isAscending) {
mIsAscending = isAscending;
return this;
}
/**
* Builds the {@link RcsThreadQueryParameters} to use in
* {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)}
*
* @return An instance of {@link RcsThreadQueryParameters} to use with the thread query.
*/
public RcsThreadQueryParameters build() {
return new RcsThreadQueryParameters(
mIsGroupThread, mParticipants, mLimit, mIsAscending);
}
}
/**
* Parcelable boilerplate below.
*/
protected RcsThreadQueryParameters(Parcel in) {
mIsGroup = in.readBoolean();
ArrayList<RcsParticipant> participantArrayList = new ArrayList<>();
in.readTypedList(participantArrayList, RcsParticipant.CREATOR);
mRcsParticipants = new HashSet<>(participantArrayList);
mLimit = in.readInt();
mIsAscending = in.readBoolean();
}
public static final Creator<RcsThreadQueryParameters> CREATOR =
new Creator<RcsThreadQueryParameters>() {
@Override
public RcsThreadQueryParameters createFromParcel(Parcel in) {
return new RcsThreadQueryParameters(in);
}
@Override
public RcsThreadQueryParameters[] newArray(int size) {
return new RcsThreadQueryParameters[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeBoolean(mIsGroup);
dest.writeTypedList(new ArrayList<>(mRcsParticipants));
dest.writeInt(mLimit);
dest.writeBoolean(mIsAscending);
}
}

View File

@@ -0,0 +1,20 @@
/*
**
** 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 android.telephony.ims;
parcelable RcsThreadQueryResult;

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 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 android.telephony.ims;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
/**
* The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken,
* RcsThreadQueryParameters)}
* call. This class allows getting the token for querying the next batch of threads in order to
* prevent handling large amounts of data at once.
*
* @hide
*/
public class RcsThreadQueryResult implements Parcelable {
private RcsThreadQueryContinuationToken mContinuationToken;
private List<RcsThread> mRcsThreads;
/**
* Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
* to create query results
*
* @hide
*/
public RcsThreadQueryResult(
RcsThreadQueryContinuationToken continuationToken, List<RcsThread> rcsThreads) {
mContinuationToken = continuationToken;
mRcsThreads = rcsThreads;
}
/**
* Returns a token to call
* {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)}
* to get the next batch of {@link RcsThread}s.
*/
public RcsThreadQueryContinuationToken nextChunkToken() {
return mContinuationToken;
}
/**
* Returns all the RcsThreads in the current query result. Call {@link
* RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)} to get the next batch of
* {@link RcsThread}s.
*/
public List<RcsThread> getThreads() {
return mRcsThreads;
}
protected RcsThreadQueryResult(Parcel in) {
// TODO - implement
}
public static final Creator<RcsThreadQueryResult> CREATOR =
new Creator<RcsThreadQueryResult>() {
@Override
public RcsThreadQueryResult createFromParcel(Parcel in) {
return new RcsThreadQueryResult(in);
}
@Override
public RcsThreadQueryResult[] newArray(int size) {
return new RcsThreadQueryResult[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO - implement
}
}

View File

@@ -16,14 +16,29 @@
package android.telephony.ims.aidl;
import android.telephony.ims.RcsParticipant;
import android.telephony.ims.Rcs1To1Thread;
import android.telephony.ims.RcsThreadQueryContinuationToken;
import android.telephony.ims.RcsThreadQueryParameters;
import android.telephony.ims.RcsThreadQueryResult;
/**
* RPC definition between RCS storage APIs and phone process.
* {@hide}
*/
interface IRcs {
// RcsMessageStore APIs
RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParameters queryParameters);
RcsThreadQueryResult getRcsThreadsWithToken(
in RcsThreadQueryContinuationToken continuationToken);
void deleteThread(int threadId);
Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
RcsParticipant createRcsParticipant(String canonicalAddress);
// RcsThread APIs
int getMessageCount(int rcsThreadId);
}

View File

@@ -11,7 +11,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4
LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4 truth-prebuilt
include $(BUILD_PACKAGE)

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tests.rcs;
package com.android.tests.ims;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.ims.RcsMessageStore;

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 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.tests.ims;
import static com.google.common.truth.Truth.assertThat;
import android.os.Bundle;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.ims.RcsParticipant;
import android.telephony.ims.RcsThreadQueryParameters;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@RunWith(AndroidJUnit4.class)
public class RcsThreadQueryParametersTest {
private RcsThreadQueryParameters mRcsThreadQueryParameters;
@Mock RcsParticipant mMockParticipant;
@Test
public void testUnparceling() {
String key = "some key";
mRcsThreadQueryParameters = RcsThreadQueryParameters.builder()
.isGroupThread(true)
.withParticipant(mMockParticipant)
.limitResultsTo(50)
.sort(true)
.build();
Bundle bundle = new Bundle();
bundle.putParcelable(key, mRcsThreadQueryParameters);
mRcsThreadQueryParameters = bundle.getParcelable(key);
assertThat(mRcsThreadQueryParameters.isGroupThread()).isTrue();
assertThat(mRcsThreadQueryParameters.getRcsParticipants()).contains(mMockParticipant);
assertThat(mRcsThreadQueryParameters.getLimit()).isEqualTo(50);
assertThat(mRcsThreadQueryParameters.isAscending()).isTrue();
}
}