当我运行该应用程序时,它会在启动时崩溃:
清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.integralblue.callerid"
android:installLocation="internalOnly" >
<!-- android:installLocation="internalOnly" because this application revolves
around a service which would not work (and would not be restarted) if the
application was to be installed on external storage and the storage unmounted -->
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- required by OpenStreetMaps -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- https://code.google.com/p/osmdroid/issues/detail?id=310 -->
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<application android:icon="@drawable/icon"
android:label="@string/app_name"
android:name=".CallerIDApplication" android:description="@string/app_description">
<activity android:name=".MainActivity" android:label="CallerID" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".PreferencesActivity" android:label="Settings" android:launchMode="singleInstance">
</activity>
<receiver android:name=".CallerIDBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<service android:exported="false" android:name=".CallerIDService" />
</application>
MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_tabs_pager);
tabHost.setup();
tabsAdapter = new TabsAdapter(this, tabHost, viewPager);
tabsAdapter.addTab(tabHost.newTabSpec("lookup").setIndicator("Lookup",drawableTabDialer),
LookupFragment.class, getIntent().getExtras());
tabsAdapter.addTab(tabHost.newTabSpec("recentCalls").setIndicator("Recent Calls",drawableTabRecent),
RecentCallsFragment.class, null);
if (savedInstanceState != null) {
tabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
}
@Override
protected void onResume() {
super.onResume();
if(versionInformationHelper.shouldPromptForNewVersion()){
showDialog(NEWER_VERSION_AVAILABLE_DIALOG);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", tabHost.getCurrentTabTag());
}
@Override
protected void onNewIntent(Intent intent){
super.onNewIntent(intent);
tabHost.setCurrentTabByTag("lookup");
// TODO I don't like how the fragment is retrieved - but I don't know of a better way.
LookupFragment lookupFragment = (LookupFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + 0);
lookupFragment.lookup(intent.getStringExtra("phoneNumber"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.help:
Intent viewIntent = new Intent("android.intent.action.VIEW", Uri.parse("http://www.integralblue.com/callerid-for-android"));
startActivity(viewIntent);
return true;
case R.id.settings:
startActivity(new Intent(this, PreferencesActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case NEWER_VERSION_AVAILABLE_DIALOG:
return versionInformationHelper.createNewVersionDialog(this);
default:
return super.onCreateDialog(id);
}
}
}
Logcat:
Increasing code cache capacity to 128KB 09-01 12:15:39.054 13625-13651/com.integralblue.callerid E/AndroidRuntime: FATAL EXCEPTION: ModernAsyncTask #1
Process: com.integralblue.callerid, PID: 13625
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:142)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.CallLogProvider from ProcessRecord{15aa181 13625:com.integralblue.callerid/u0a396} (pid=13625, uid=10396) requires android.permission.READ_CALL_LOG or android.permission.WRITE_CALL_LOG
at android.os.Parcel.readException(Parcel.java:1693)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4912)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:6043)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2474)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1521)
at android.content.ContentResolver.query(ContentResolver.java:520)
at android.support.v4.content.ContentResolverCompatJellybean.query(ContentResolverCompatJellybean.java:29)
at android.support.v4.content.ContentResolverCompat$ContentResolverCompatImplJB.query(ContentResolverCompat.java:57)
at android.support.v4.content.ContentResolverCompat.query(ContentResolverCompat.java:125)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:59)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:37)
at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:296)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:54)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:42)
at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:128)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762) 09-01 12:15:39.080 13625-13625/com.integralblue.callerid D/ViewRootImpl@65b2e58[MainActivity]: Relayout returned: oldFrame=[0,0][0,0] newFrame=[0,0][720,1280] result=0x27 surface={isValid=true -321540096} surfaceGenerationChanged=true
mHardwareRenderer.initialize() mSurface={isValid=true -321540096} hwInitialized=true 09-01 12:15:39.093 13625-13625/com.integralblue.callerid D/AbsListView: in onLayout changed 09-01 12:15:39.094 13625-13650/com.integralblue.callerid I/OpenGLRenderer: Initialized EGL, version 1.4 09-01 12:15:39.094 13625-13650/com.integralblue.callerid D/OpenGLRenderer: Swap behavior 1
答案 0 :(得分:1)
您需要设置运行时权限。
$ cd bar
$ realpath --no-symlinks file
/home/pet3r/test/foo/file
与写呼叫日志相同
您的MainActivity应该会这样
String wantPermission = Manifest.permission.READ_CALL_LOG;
// called in a standard activity, use ContextCompat.checkSelfPermission for AppCompActivity
int permissionCheck = checkSelfPermission(this, wantPermission);
if (!permissionCheck == PackageManager.PERMISSION_GRANTED) {
// user may have declined earlier, ask Android if we should show him a reason
if (shouldShowRequestPermissionRationale(MainActivity.this, wantPermission)) {
// show an explanation to the user
} else {
// request the permission.
// CALLBACK_NUMBER is a integer constants
requestPermissions(MainActivity.this, new String[]{wantPermission}, CALLBACK_NUMBER);
}
} else {
// got permission, use it
}