我正在尝试开发一个简单的应用程序,将记录插入手机通讯录中。看起来我没有权限问题,但系统仍不允许创建记录:
07-28 18:11:44.799 2304 10616 I UpdateIcingCorporaServi: Updating corpora: APPS=com.example.aero.myapplication, CONTACTS=MAYBE
07-28 18:11:45.362 2304 10648 I UpdateIcingCorporaServi: Updating corpora: APPS=com.example.aero.myapplication.test, CONTACTS=MAYBE
07-28 18:11:45.651 10663 10678 I GrantPermissionCallable: Permission: android.permission.WRITE_CONTACTS is already granted!
07-28 18:11:46.255 10663 10678 I OK : contact Permission to record allowed
07-28 18:11:46.255 10663 10678 D Info : Creating contact: 123456789
07-28 18:11:46.259 2097 2114 E DatabaseUtils: java.lang.SecurityException: Proxy package com.android.providers.contacts from uid 10001 or calling package com.example.aero.myapplication.test from uid 10097 not allowed to perform WRITE_CONTACTS
07-28 18:11:46.260 10663 10678 E Error : Exception encountered while inserting contact: java.lang.SecurityException: Proxy package com.android.providers.contacts from uid 10001 or calling package com.example.aero.myapplication.test from uid 10097 not allowed to perform WRITE_CONTACTS
有什么想法吗?为什么这样神秘? 一旦我运行应用程序,它会安装两个apk:
$ adb push /Users/aero/AndroidStudioProjects/MyApplication/app/build/outputs/apk/app-debug.apk /data/local/tmp/com.example.aero.myapplication
$ adb shell pm install -r "/data/local/tmp/com.example.aero.myapplication"
并且
$ adb push /Users/aero/AndroidStudioProjects/MyApplication/app/build/outputs/apk/app-debug-androidTest.apk /data/local/tmp/com.example.aero.myapplication.test
$ adb shell pm install -r "/data/local/tmp/com.example.aero.myapplication.test"
只有 com.example.aero.myapplication 在系统中拥有权限,com.example.aero.myapplication.test 没有任何权限。我有点迷惑了。
package com.example.aero.myapplication;
import android.Manifest;
import android.app.Instrumentation;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.provider.ContactsContract;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import org.junit.Before;
import org.junit.Rule;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
@RunWith(AndroidJUnit4.class)
public class MainActivity{
@Rule
public GrantPermissionRule permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_CONTACTS);
public Instrumentation instrumentation;
private UiDevice mDevice;
private static final int RECORD_REQUEST_CODE = 101;
@Before
public void before() {
// Initialize UiDevice instance
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
//instrumentation = InstrumentationRegistry.getInstrumentation();
assertThat(mDevice, notNullValue());
// Start from the home screen
mDevice.pressHome();
}
@org.junit.Test
public void test() throws InterruptedException {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
String NAME = "TEST RECORD";
String NMBR = "123456789";
CreatePhoneBookEntry(context, NAME, NMBR);
}
public void CreatePhoneBookEntry(Context context, String NAME, String NMBR) {
//ActivityCompat.requestPermissions(context,
// new String[]{Manifest.permission.WRITE_CONTACTS},
// RECORD_REQUEST_CODE)
int permission = ActivityCompat.checkSelfPermission(context,
Manifest.permission.WRITE_CONTACTS);
if (permission != PackageManager.PERMISSION_GRANTED) {
Log.i("Error", "contact Permission to record denied");
} else {
Log.i("OK", "contact Permission to record allowed");
};
/*
* Gets values from the UI
*/
// Creates a new array of ContentProviderOperation objects.
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
/*
* Creates a new raw contact with its account type (server type) and account name
* (user's account). Remember that the display name is not stored in this row, but in a
* StructuredName data row. No other data is required.
*/
ContentProviderOperation.Builder op =
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
// Builds the operation and adds it to the array of operations
ops.add(op.build());
// Creates the display name for the new raw contact, as a StructuredName data row.
op =
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
/*
* withValueBackReference sets the value of the first argument to the value of
* the ContentProviderResult indexed by the second argument. In this particular
* call, the raw contact ID column of the StructuredName data row is set to the
* value of the result returned by the first operation, which is the one that
* actually adds the raw contact row.
*/
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
// Sets the data row's MIME type to StructuredName
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
// Sets the data row's display name to the name in the UI.
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, NAME);
// Builds the operation and adds it to the array of operations
ops.add(op.build());
// Inserts the specified phone number and type as a Phone data row
op =
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
/*
* Sets the value of the raw contact id column to the new raw contact ID returned
* by the first operation in the batch.
*/
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
// Sets the data row's MIME type to Phone
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
// Sets the phone number and type
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, NMBR)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, "MOBILE");
// Builds the operation and adds it to the array of operations
ops.add(op.build());
// Ask the Contacts Provider to create a new contact
Log.d("Info", "Creating contact: " + NMBR);
/*
* Applies the array of ContentProviderOperation objects in batch. The results are
* discarded.
*/
try {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
// Log exception
Log.e("Error", "Exception encountered while inserting contact: " + e);
}
}
}