Reputation: 47
I am a newbie here and this project is my first android project. I'm trying to display the device's call log on the FragmentCalls.java. App crashes on the device even after I requesting run-time permission.
Actually, app crashes on launch. Please, help!
This is my error log.
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.CallLogProvider from ProcessRecord{7d3e3e4 30945:package.name.google/u0a200} (pid=30945, uid=10200) requires android.permission.READ_CALL_LOG or android.permission.WRITE_CALL_LOG
at package.name.google.fragments.FragmentCalls.getCallLogs(FragmentCalls.java:68)
at package.name.google.fragments.FragmentCalls.onCreateView(FragmentCalls.java:46)
FragmentCalls.java
package package.name.google.fragments;
import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.CallLog;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import site.mobilesocial.google.R;
import site.mobilesocial.google.adapters.CallsRvAdapter;
import site.mobilesocial.google.models.ModelCalls;
@SuppressWarnings("WeakerAccess,FieldCanBeLocal")
public class FragmentCalls extends Fragment {
private View v;
private RecyclerView recyclerView;
public FragmentCalls() {
}
@SuppressWarnings("UnnecessaryLocalVariable")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
v = inflater.inflate(R.layout.frag_calls, container, false);
recyclerView = v.findViewById(R.id.rv_calls);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
RecyclerView.LayoutManager layoutManager = linearLayoutManager;
recyclerView.setLayoutManager(layoutManager);
**/*This is line 46*/ CallsRvAdapter adapter = new CallsRvAdapter(getContext(), getCallLogs()); //This is line 46**
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setHasFixedSize(true);
return v;
}
@SuppressWarnings("LogNotTimber")
private List<ModelCalls> getCallLogs() {
List<ModelCalls> list = new ArrayList<>();
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.READ_CALL_LOG}, 1);
}
/*This is line 68*/ **Cursor cursor = getContext().getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + " DESC");** //This is line 68
assert cursor != null;
int number = cursor.getColumnIndex(CallLog.Calls.NUMBER);
int date = cursor.getColumnIndex(CallLog.Calls.DATE);
// int info = cursor.getColumnIndex(CallLog.Calls.TYPE);
cursor.moveToNext();
while (cursor.moveToNext()) {
Date date1 = new Date(Long.valueOf(cursor.getString(date)));
list.add(new ModelCalls(cursor.getString(number), date1.toLocaleString()));// cursor.getString(info)));
Log.d("MiC:: ", cursor.getString(number));
}
return list;
}
}
MainActivity.java
package package.name.google;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.holder.BadgeStyle;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
import com.mikepenz.materialdrawer.model.SectionDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IProfile;
import java.util.HashMap;
import java.util.Objects;
import site.mobilesocial.google.adapters.ViewPagerAdapter;
import site.mobilesocial.google.fragments.FragmentCalls;
import site.mobilesocial.google.helper.DatabaseHandler;
import site.mobilesocial.google.helper.Functions;
import site.mobilesocial.google.helper.SessionManager;
@SuppressWarnings("FieldCanBeLocal")
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private SessionManager session;
private DatabaseHandler db;
private AccountHeader headerResult = null;
private Drawer result = null;
private Toast toast = null;
private ViewPager viewPager;
private ProgressDialog pDialog;
private HashMap<String,String> user = new HashMap<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewpager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new FragmentCalls(), "Calls");
viewPager.setAdapter(adapter);
// Progress dialog
pDialog = new ProgressDialog(this);
pDialog.setCancelable(false);
db = new DatabaseHandler(getApplicationContext());
user = db.getUserDetails();
// session manager
session = new SessionManager(getApplicationContext());
if (!session.isLoggedIn()) {
logoutUser();
}
// Hide Keyboard
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setBackground(ContextCompat.getDrawable(getBaseContext(), R.color.md_black_1000));
// toolbar.setLogo(R.drawable.toolbarlogo);
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(null);
createAccountHeader();
result = new DrawerBuilder(this)
.withToolbar(toolbar)
.withAccountHeader(headerResult)
.withTranslucentStatusBar(true)
.withActionBarDrawerToggle(true)
.withActionBarDrawerToggleAnimated(true)
.withInnerShadow(true)
.withSliderBackgroundColor(Color.WHITE)
.withActionBarDrawerToggle(true)
.withTranslucentNavigationBar(true)
.withOnDrawerListener(new Drawer.OnDrawerListener() {
@Override
public void onDrawerOpened(View drawerView) {
Functions.hideSoftKeyboard(MainActivity.this);
}
@Override
public void onDrawerClosed(View drawerView) {
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}
})
.addDrawerItems(initDrawerItems())
.withSavedInstance(savedInstanceState)
.withDrawerGravity(Gravity.START)
.addStickyDrawerItems(new SecondaryDrawerItem().withIdentifier(7).withName(R.string.logout).withIcon(FontAwesome.Icon.faw_lock).withSelectable(false))
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override
public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
if (drawerItem != null) {
switch ((int) drawerItem.getIdentifier()) {
case 7:
logoutUser();
}
}
return false;
}
})
.build();
result.getActionBarDrawerToggle().setDrawerIndicatorEnabled(true);
askPermissions();
}
private void askPermissions() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS}, 1);
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CALL_LOG}, 1);
} else {
finish();
}
}
private void createAccountHeader() {
user.get("name");
user.get("email");
headerResult = new AccountHeaderBuilder()
.withActivity(this)
.withTextColorRes(R.color.material_drawer_dark_header_selection_text)
.addProfiles(
new ProfileDrawerItem().withIdentifier(8).withName(user.get("name")).withEmail(user.get("email"))
)
.withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
@Override
public boolean onProfileChanged(View view, IProfile profile, boolean current) {
profileClick(profile);
return false;
}
})
.build();
}
private void profileClick(IProfile profile) {
switch ((int) profile.getIdentifier()) {
case 8:
toast = Toast.makeText(getApplicationContext(),
user.get("name"),
Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
break;
}
}
@NonNull
private IDrawerItem[] initDrawerItems() {
return new IDrawerItem[]{new PrimaryDrawerItem().withIdentifier(0).withName(R.string.drawer_item_home).withIcon(FontAwesome.Icon.faw_home),
new PrimaryDrawerItem().withIdentifier(1).withName("test").withIcon(FontAwesome.Icon.faw_user_plus).withSetSelected(true),
new PrimaryDrawerItem().withIdentifier(2).withName("test2").withIcon(FontAwesome.Icon.faw_eye).withBadge("19").withSelectable(false).withBadgeStyle(new BadgeStyle().withTextColor(Color.WHITE).withColorRes(R.color.md_red_700)),
new SectionDrawerItem().withIdentifier(3).withName("test3"),
new SecondaryDrawerItem().withIdentifier(4).withName("test4").withIcon(FontAwesome.Icon.faw_cogs).withSelectable(false),
new SecondaryDrawerItem().withIdentifier(5).withName("test5").withIcon(FontAwesome.Icon.faw_asterisk).withSelectable(false),
new SecondaryDrawerItem().withIdentifier(6).withName("test6").withIcon(FontAwesome.Icon.faw_question_circle).withSelectable(false)
};
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState = result.saveInstanceState(outState);
super.onSaveInstanceState(outState);
}
boolean doubleBackToExitPressedOnce = false;
@Override
public void onBackPressed() {
if (result != null && result.isDrawerOpen()) {
result.closeDrawer();
} else {
if (doubleBackToExitPressedOnce)
super.onBackPressed();
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "한번 더 누르면 종료됩니다", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
}
private void logoutUser() {
session.setLogin(false);
// Launching the login activity
Functions logout = new Functions();
logout.logoutUser(getApplicationContext());
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}
Upvotes: 1
Views: 2500
Reputation: 91
I would also suggest you to try out this library. Dexter is an Android library that simplifies the process of requesting permissions at runtime.
https://github.com/Karumi/Dexter
Sample permission request:
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
@Override public void onPermissionGranted(PermissionGrantedResponse response) {/* ... */}
@Override public void onPermissionDenied(PermissionDeniedResponse response) {/* ... */}
@Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {/* ... */}
}).check();
Upvotes: 0
Reputation: 47
I found a solution
Removed askPermission() from my MainActivity and changed FragmentCalls.java like this and this is worked
FragmentCalls.java
package site.mobilesocial.google.fragments;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.CallLog;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import site.mobilesocial.google.R;
import site.mobilesocial.google.adapters.CallsRvAdapter;
import site.mobilesocial.google.models.ModelCalls;
import static android.Manifest.permission.READ_CALL_LOG;
@SuppressWarnings("WeakerAccess,FieldCanBeLocal")
public class FragmentCalls extends Fragment {
private View v;
private RecyclerView recyclerView;
private static final int REQUEST_PERMISSION_CONTACTS = 1;
public FragmentCalls() {
}
@SuppressWarnings("UnnecessaryLocalVariable")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
v = inflater.inflate(R.layout.frag_calls, container, false);
recyclerView = v.findViewById(R.id.rv_calls);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
RecyclerView.LayoutManager layoutManager = linearLayoutManager;
recyclerView.setLayoutManager(layoutManager);
if (ContextCompat.checkSelfPermission(getActivity(), READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
// We have access. Life is good.
CallsRvAdapter adapter = new CallsRvAdapter(getContext(), getCallLogs());
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setHasFixedSize(true);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), READ_CALL_LOG)) {
// We've been denied once before. Explain why we need the permission, then ask again.
Toast.makeText(getContext(), "Permission is needed", Toast.LENGTH_SHORT).show();
requestPermissions(new String[]{READ_CALL_LOG}, REQUEST_PERMISSION_CONTACTS);
} else {
// We've never asked. Just do it.
requestPermissions(new String[]{READ_CALL_LOG}, REQUEST_PERMISSION_CONTACTS);
}
return v;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
CallsRvAdapter adapter = new CallsRvAdapter(getContext(), getCallLogs());
} else {
// We were not granted permission this time, so don't try to show the contact picker
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@SuppressWarnings("LogNotTimber")
private List<ModelCalls> getCallLogs() {
List<ModelCalls> list = new ArrayList<>();
Cursor cursor = getContext().getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + " DESC");
assert cursor != null;
int number = cursor.getColumnIndex(CallLog.Calls.NUMBER);
int date = cursor.getColumnIndex(CallLog.Calls.DATE);
// int info = cursor.getColumnIndex(CallLog.Calls.TYPE);
cursor.moveToNext();
while (cursor.moveToNext()) {
Date date1 = new Date(Long.valueOf(cursor.getString(date)));
list.add(new ModelCalls(cursor.getString(number), date1.toLocaleString()));// cursor.getString(info)));
Log.d("MiC:: ", cursor.getString(number));
}
return list;
}
}
Thats it thanks.
Upvotes: 0
Reputation: 3739
Add these permissions in manifest if target version is less then 23
<uses-permission android:name="android.permission.read_contacts" />
<uses-permission android:name="android.permission.read_phone_state" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
also check manifest intent filter for launcher activity, it should be present
<intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter>
Upvotes: 0
Reputation: 16429
Result of permissions request is asynchronous. You should return the function after requesting the permissions and perform the required operations inside the method onRequestPermissionsResult
.
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.READ_CALL_LOG}, 1);
return;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
// check if permission has been granted and do your operations.
}
Also don't request permissions from a method which is supposed to return something. Make sure you already have permissions before accessing the call logs or other critical information.
You can find a lot of tutorials and documentations about run-time permissions online. The official one is here.
Upvotes: 2