blob: aa35b7a10309d830c420ddd79898d88f406823f0 [file] [log] [blame]
/*
* Copyright (C) 2011 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.providers.contacts;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.CallLog.Calls;
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Status;
import android.provider.VoicemailContract.Voicemails;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.common.io.MoreCloseables;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
/**
* Unit tests for {@link VoicemailContentProvider}.
*
* Run the test like this:
* <code>
* runtest -c com.android.providers.contacts.VoicemailProviderTest contactsprov
* </code>
*/
// TODO: Test that calltype and voicemail_uri are auto populated by the provider.
@SmallTest
public class VoicemailProviderTest extends BaseVoicemailProviderTest {
/** Fields specific to call_log provider that should not be exposed by voicemail provider. */
private static final String[] CALLLOG_PROVIDER_SPECIFIC_COLUMNS = {
Calls.CACHED_NAME,
Calls.CACHED_NUMBER_LABEL,
Calls.CACHED_NUMBER_TYPE,
Calls.TYPE,
Calls.VOICEMAIL_URI,
Calls.COUNTRY_ISO
};
/** Total number of columns exposed by voicemail provider. */
private static final int NUM_VOICEMAIL_FIELDS = 18;
@Override
protected void setUp() throws Exception {
super.setUp();
setUpForOwnPermission();
}
/** Returns the appropriate /voicemail URI. */
private Uri voicemailUri() {
return mUseSourceUri ?
Voicemails.buildSourceUri(mActor.packageName) : Voicemails.CONTENT_URI;
}
/** Returns the appropriate /status URI. */
private Uri statusUri() {
return mUseSourceUri ?
Status.buildSourceUri(mActor.packageName) : Status.CONTENT_URI;
}
public void testInsert() throws Exception {
Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
// We create on purpose a new set of ContentValues here, because the code above modifies
// the copy it gets.
assertStoredValues(uri, getTestVoicemailValues());
assertSelection(uri, getTestVoicemailValues(), Voicemails._ID, ContentUris.parseId(uri));
assertEquals(1, countFilesInTestDirectory());
}
public void testInsertReadMessageIsNotNew() throws Exception {
ContentValues values = getTestReadVoicemailValues();
Uri uri = mResolver.insert(voicemailUri(), values);
String[] projection = {Voicemails.NUMBER, Voicemails.DATE, Voicemails.DURATION,
Voicemails.TRANSCRIPTION, Voicemails.IS_READ, Voicemails.HAS_CONTENT,
Voicemails.SOURCE_DATA, Voicemails.STATE,
};
Cursor c = mResolver.query(uri, projection, Calls.NEW + "=0", null,
null);
try {
assertEquals("Record count", 1, c.getCount());
c.moveToFirst();
assertEquals(1, countFilesInTestDirectory());
assertCursorValues(c, values);
} catch (Error e) {
TestUtils.dumpCursor(c);
throw e;
} finally {
c.close();
}
}
// Test to ensure that media content can be written and read back.
public void testFileContent() throws Exception {
Uri uri = insertVoicemail();
OutputStream out = mResolver.openOutputStream(uri);
byte[] outBuffer = {0x1, 0x2, 0x3, 0x4};
out.write(outBuffer);
out.flush();
out.close();
InputStream in = mResolver.openInputStream(uri);
byte[] inBuffer = new byte[4];
int numBytesRead = in.read(inBuffer);
assertEquals(numBytesRead, outBuffer.length);
MoreAsserts.assertEquals(outBuffer, inBuffer);
// No more data should be left.
assertEquals(-1, in.read(inBuffer));
in.close();
}
public void testUpdate() {
Uri uri = insertVoicemail();
ContentValues values = new ContentValues();
values.put(Voicemails.NUMBER, "1-800-263-7643");
values.put(Voicemails.DATE, 2000);
values.put(Voicemails.DURATION, 40);
values.put(Voicemails.TRANSCRIPTION, "Testing 123");
values.put(Voicemails.STATE, 2);
values.put(Voicemails.HAS_CONTENT, 1);
values.put(Voicemails.SOURCE_DATA, "foo");
values.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, "dummy_name");
values.put(Voicemails.PHONE_ACCOUNT_ID, "dummy_account");
int count = mResolver.update(uri, values, null, null);
assertEquals(1, count);
assertStoredValues(uri, values);
}
public void testUpdateOwnPackageVoicemail_NotDirty() {
final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
mResolver.update(uri, new ContentValues(), null, null);
// Updating a package's own voicemail should not make the voicemail dirty.
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.DIRTY, "0");
assertStoredValues(uri, values);
}
public void testUpdateOwnPackageVoicemail_RemovesDirtyStatus() {
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.DIRTY, "1");
final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
mResolver.update(uri, new ContentValues(), null, null);
// At this point, the voicemail should be set back to not dirty.
ContentValues newValues = getTestVoicemailValues();
newValues.put(Voicemails.DIRTY, "0");
assertStoredValues(uri, newValues);
}
public void testDeleteOwnPackageVoicemail_DeletesRow() {
setUpForFullPermission();
final Uri ownVoicemail = insertVoicemail();
assertEquals(1, getCount(voicemailUri(), null, null));
mResolver.delete(ownVoicemail, null, null);
assertEquals(0, getCount(ownVoicemail, null, null));
}
public void testDeleteOtherPackageVoicemail_SetsDirtyStatus() {
setUpForFullPermission();
final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
assertEquals(1, getCount(voicemailUri(), null, null));
// Clear the mapping for our own UID so that this doesn't look like an internal transaction.
mPackageManager.removePackage(Process.myUid());
mResolver.delete(anotherVoicemail, null, null);
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.DIRTY, "1");
values.put(Voicemails.DELETED, "1");
assertEquals(1, getCount(anotherVoicemail, null, null));
assertStoredValues(anotherVoicemail, values);
}
public void testDelete() {
Uri uri = insertVoicemail();
int count = mResolver.delete(voicemailUri(), Voicemails._ID + "="
+ ContentUris.parseId(uri), null);
assertEquals(1, count);
assertEquals(0, getCount(uri, null, null));
}
public void testGetType_ItemUri() throws Exception {
// Random item uri.
assertEquals(Voicemails.ITEM_TYPE,
mResolver.getType(ContentUris.withAppendedId(Voicemails.CONTENT_URI, 100)));
// Item uri of an inserted voicemail.
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.MIME_TYPE, "foo/bar");
Uri uri = mResolver.insert(voicemailUri(), values);
assertEquals(Voicemails.ITEM_TYPE, mResolver.getType(uri));
}
public void testGetType_DirUri() throws Exception {
assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.CONTENT_URI));
assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.buildSourceUri("foo")));
}
// Test to ensure that without full permission it is not possible to use the base uri (i.e. with
// no package URI specified).
public void testMustUsePackageUriWithoutFullPermission() {
setUpForOwnPermission();
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.insert(Voicemails.CONTENT_URI, getTestVoicemailValues());
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.update(Voicemails.CONTENT_URI, getTestVoicemailValues(), null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.query(Voicemails.CONTENT_URI, null, null, null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.delete(Voicemails.CONTENT_URI, null, null);
}
});
}
public void testPermissions_InsertAndQuery() {
setUpForFullPermission();
// Insert two records - one each with own and another package.
insertVoicemail();
insertVoicemailForSourcePackage("another-package");
assertEquals(2, getCount(voicemailUri(), null, null));
// Now give away full permission and check that only 1 message is accessible.
setUpForOwnPermission();
assertEquals(1, getCount(voicemailUri(), null, null));
// Once again try to insert message for another package. This time
// it should fail.
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
insertVoicemailForSourcePackage("another-package");
}
});
setUpForNoPermission();
mUseSourceUri = false;
// With the READ_ALL_VOICEMAIL permission, we should now be able to read all voicemails
mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
assertEquals(2, getCount(voicemailUri(), null, null));
// An insert for another package should still fail
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
insertVoicemailForSourcePackage("another-package");
}
});
}
public void testPermissions_UpdateAndDelete() {
setUpForFullPermission();
// Insert two records - one each with own and another package.
final Uri ownVoicemail = insertVoicemail();
final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
assertEquals(2, getCount(voicemailUri(), null, null));
// Now give away full permission and check that we can update and delete only
// the own voicemail.
setUpForOwnPermission();
mResolver.update(withSourcePackageParam(ownVoicemail),
getTestVoicemailValues(), null, null);
mResolver.delete(withSourcePackageParam(ownVoicemail), null, null);
// However, attempting to update or delete another-package's voicemail should fail.
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.update(anotherVoicemail, null, null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.delete(anotherVoicemail, null, null);
}
});
// If we have the manage voicemail permission, we should be able to both update voicemails
// from all packages.
setUpForNoPermission();
mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION);
mResolver.update(anotherVoicemail, getTestVoicemailValues(), null, null);
// Now add the read voicemail permission temporarily to verify that the update actually
// worked
mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
assertStoredValues(anotherVoicemail, getTestVoicemailValues());
mActor.removePermissions(READ_VOICEMAIL_PERMISSION);
mResolver.delete(anotherVoicemail, null, null);
// Now add the read voicemail permission temporarily to verify that the voicemail is
// deleted.
mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
assertEquals(0, getCount(anotherVoicemail, null, null));
}
private Uri withSourcePackageParam(Uri uri) {
return uri.buildUpon()
.appendQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, mActor.packageName)
.build();
}
public void testUriPermissions() {
setUpForFullPermission();
final Uri uri1 = insertVoicemail();
final Uri uri2 = insertVoicemail();
// Give away all permissions before querying. Access to both uris should be denied.
setUpForNoPermission();
checkHasNoAccessToUri(uri1);
checkHasNoAccessToUri(uri2);
// Just grant permission to uri1. uri1 should pass but uri2 should still fail.
mActor.addUriPermissions(uri1);
checkHasReadOnlyAccessToUri(uri1);
checkHasNoAccessToUri(uri2);
// Cleanup.
mActor.removeUriPermissions(uri1);
}
/*
* Checks that the READ_ALL_VOICEMAIL permission provides read access to a uri.
*/
public void testUriPermissions_ReadAccess() {
setUpForFullPermission();
final Uri uri1 = insertVoicemail();
// Give away all permissions before querying. Access should be denied.
setUpForNoPermission();
mUseSourceUri = false;
checkHasNoAccessToUri(uri1);
mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
checkHasReadAccessToUri(uri1);
}
/*
* Checks that the MANAGE_VOICEMAIL permission provides write access to a uri.
*/
public void testUriPermissions_WriteAccess() {
setUpForFullPermission();
final Uri uri1 = insertVoicemail();
// Give away all permissions before querying. Access should be denied.
setUpForNoPermission();
checkHasNoAccessToUri(uri1);
mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION);
checkHasUpdateAndDeleteAccessToUri(uri1);
}
private void checkHasNoAccessToUri(final Uri uri) {
checkHasNoReadAccessToUri(uri);
checkHasNoWriteAccessToUri(uri);
}
private void checkHasReadOnlyAccessToUri(final Uri uri) {
checkHasReadAccessToUri(uri);
checkHasNoWriteAccessToUri(uri);
}
private void checkHasReadAccessToUri(final Uri uri) {
Cursor cursor = null;
try {
cursor = mResolver.query(uri, null, null ,null, null);
assertEquals(1, cursor.getCount());
try {
ParcelFileDescriptor fd = mResolver.openFileDescriptor(uri, "r");
assertNotNull(fd);
fd.close();
} catch (FileNotFoundException e) {
fail(e.getMessage());
} catch (IOException e) {
fail(e.getMessage());
}
} finally {
MoreCloseables.closeQuietly(cursor);
}
}
private void checkHasNoReadAccessToUri(final Uri uri) {
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.query(uri, null, null ,null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
try {
mResolver.openFileDescriptor(uri, "r");
} catch (FileNotFoundException e) {
fail(e.getMessage());
}
}
});
}
private void checkHasUpdateAndDeleteAccessToUri(final Uri uri) {
mResolver.update(uri, getTestVoicemailValues(), null, null);
mResolver.delete(uri, null, null);
}
private void checkHasNoWriteAccessToUri(final Uri uri) {
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.update(uri, getTestVoicemailValues(), null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.delete(uri, null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
try {
mResolver.openFileDescriptor(uri, "w");
} catch (FileNotFoundException e) {
fail(e.getMessage());
}
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
try {
mResolver.openFileDescriptor(uri, "rw");
} catch (FileNotFoundException e) {
fail(e.getMessage());
}
}
});
}
// Test to ensure that all operations fail when no voicemail permission is granted.
public void testNoPermissions() {
setUpForNoPermission();
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.insert(voicemailUri(), getTestVoicemailValues());
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.update(voicemailUri(), getTestVoicemailValues(), null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.query(voicemailUri(), null, null, null, null);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.delete(voicemailUri(), null, null);
}
});
}
// Test to check that none of the call_log provider specific fields are
// insertable through voicemail provider.
public void testCannotAccessCallLogSpecificFields_Insert() {
for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
final ContentValues values = getTestVoicemailValues();
values.put(callLogColumn, "foo");
EvenMoreAsserts.assertThrows("Column: " + callLogColumn,
IllegalArgumentException.class, new Runnable() {
@Override
public void run() {
mResolver.insert(voicemailUri(), values);
}
});
}
}
// Test to check that none of the call_log provider specific fields are
// exposed through voicemail provider query.
public void testCannotAccessCallLogSpecificFields_Query() {
// Query.
Cursor cursor = mResolver.query(voicemailUri(), null, null, null, null);
List<String> columnNames = Arrays.asList(cursor.getColumnNames());
assertEquals(NUM_VOICEMAIL_FIELDS, columnNames.size());
// None of the call_log provider specific columns should be present.
for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
assertFalse("Unexpected column: '" + callLogColumn + "' returned.",
columnNames.contains(callLogColumn));
}
}
// Test to check that none of the call_log provider specific fields are
// updatable through voicemail provider.
public void testCannotAccessCallLogSpecificFields_Update() {
for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
final Uri insertedUri = insertVoicemail();
final ContentValues values = getTestVoicemailValues();
values.put(callLogColumn, "foo");
EvenMoreAsserts.assertThrows("Column: " + callLogColumn,
IllegalArgumentException.class, new Runnable() {
@Override
public void run() {
mResolver.update(insertedUri, values, null, null);
}
});
}
}
// Tests for voicemail status table.
public void testStatusInsert() throws Exception {
ContentValues values = getTestStatusValues();
Uri uri = mResolver.insert(statusUri(), values);
assertStoredValues(uri, values);
assertSelection(uri, values, Status._ID, ContentUris.parseId(uri));
}
// Test to ensure that duplicate entries for the same package still end up as the same record.
public void testStatusInsertDuplicate() throws Exception {
setUpForFullPermission();
ContentValues values = getTestStatusValues();
assertNotNull(mResolver.insert(statusUri(), values));
assertEquals(1, getCount(statusUri(), null, null));
// Insertion request for the same package should fail with no change in count.
values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_NO_CONNECTION);
assertNull(mResolver.insert(statusUri(), values));
assertEquals(1, getCount(statusUri(), null, null));
// Now insert entry for another source package, and it should end up as a separate record.
values.put(Status.SOURCE_PACKAGE, "another.package");
assertNotNull(mResolver.insert(statusUri(), values));
assertEquals(2, getCount(statusUri(), null, null));
}
public void testStatusUpdate() throws Exception {
Uri uri = insertTestStatusEntry();
ContentValues values = getTestStatusValues();
values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_NO_CONNECTION);
values.put(Status.NOTIFICATION_CHANNEL_STATE,
Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING);
int count = mResolver.update(uri, values, null, null);
assertEquals(1, count);
assertStoredValues(uri, values);
}
public void testStatusDelete() {
Uri uri = insertTestStatusEntry();
int count = mResolver.delete(statusUri(), Status._ID + "="
+ ContentUris.parseId(uri), null);
assertEquals(1, count);
assertEquals(0, getCount(uri, null, null));
}
public void testStatusGetType() throws Exception {
// Item URI.
Uri uri = insertTestStatusEntry();
assertEquals(Status.ITEM_TYPE, mResolver.getType(uri));
// base URIs.
assertEquals(Status.DIR_TYPE, mResolver.getType(Status.CONTENT_URI));
assertEquals(Status.DIR_TYPE, mResolver.getType(Status.buildSourceUri("foo")));
}
// Basic permission checks for the status table.
public void testStatusPermissions() throws Exception {
final ContentValues values = getTestStatusValues();
// Inserting for another package should fail with any of the URIs.
values.put(Status.SOURCE_PACKAGE, "another.package");
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.insert(Status.CONTENT_URI, values);
}
});
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.insert(Status.buildSourceUri(mActor.packageName), values);
}
});
// But insertion with own package should succeed with the right uri.
values.put(Status.SOURCE_PACKAGE, mActor.packageName);
final Uri uri = mResolver.insert(Status.buildSourceUri(mActor.packageName), values);
assertNotNull(uri);
// Updating source_package should not work as well.
values.put(Status.SOURCE_PACKAGE, "another.package");
EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
@Override
public void run() {
mResolver.update(uri, values, null, null);
}
});
}
// File operation is not supported by /status URI.
public void testStatusFileOperation() throws Exception {
final Uri uri = insertTestStatusEntry();
EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() {
@Override
public void run() {
try {
mResolver.openOutputStream(uri);
} catch (FileNotFoundException e) {
fail("Unexpected exception " + e);
}
}
});
EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() {
@Override
public void run() {
try {
mResolver.openInputStream(uri);
} catch (FileNotFoundException e) {
fail("Unexpected exception " + e);
}
}
});
}
/**
* Inserts a voicemail record with no source package set. The content provider
* will detect source package.
*/
private Uri insertVoicemail() {
return mResolver.insert(voicemailUri(), getTestVoicemailValues());
}
/** Inserts a voicemail record for the specified source package. */
private Uri insertVoicemailForSourcePackage(String sourcePackage) {
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.SOURCE_PACKAGE, sourcePackage);
return mResolver.insert(voicemailUri(), values);
}
private ContentValues getTestVoicemailValues() {
ContentValues values = new ContentValues();
values.put(Voicemails.NUMBER, "1-800-4664-411");
values.put(Voicemails.DATE, 1000);
values.put(Voicemails.DURATION, 30);
values.put(Voicemails.TRANSCRIPTION, "Testing 123");
values.put(Voicemails.IS_READ, 0);
values.put(Voicemails.HAS_CONTENT, 0);
values.put(Voicemails.SOURCE_DATA, "1234");
values.put(Voicemails.STATE, Voicemails.STATE_INBOX);
return values;
}
private ContentValues getTestReadVoicemailValues() {
ContentValues values = getTestVoicemailValues();
values.put(Voicemails.IS_READ, 1);
return values;
}
private Uri insertTestStatusEntry() {
return mResolver.insert(statusUri(), getTestStatusValues());
}
private ContentValues getTestStatusValues() {
ContentValues values = new ContentValues();
values.put(Status.SOURCE_PACKAGE, mActor.packageName);
values.put(Status.VOICEMAIL_ACCESS_URI, "tel:901");
values.put(Status.SETTINGS_URI, "com.example.voicemail.source.SettingsActivity");
values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_OK);
values.put(Status.NOTIFICATION_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE_OK);
return values;
}
}