I have an application that depends on location services being enabled.
Thus, when the user starts the application- a dialog box appears and it checks if the location service is enabled or not. However, I want the application to pause until the user goes to the settings page (Which he is redirected to on clicking "okay" in the dialog box) and enables location services. Once he does, he should be able to return back to the MainActivity and the code should continue where he left off.
If I don't let the app pause, the code just continues and tries to execute code that requires the location services to be on, and the app crashes.
I currently have this, so how can I modify it so that it waits?
if(!location_enabled) {
// notify user
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setMessage("Location services are currently not " +
"enabled. You must enable this in order to continue. Would you like to do this now?");
dialog.setPositiveButton("Take me to location services", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
// WAIT UNTIL LOCATION SERVICES ENABLED
}
});
dialog.setNegativeButton(context.getString(R.string.Cancel), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
//EXIT APPLICATION
}
});
dialog.show();
}
if(location_enabled) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) {
//DO FANCY STUFF WITH LOCATION
}
}
You can easily use startActivityForResult in your case.
When you're starting the settings to enable your location, you may start the intent like this.
// Declare a global variable first
private final int ACTION_LOCATION_SETTING = 100;
// Now change the onClickListener like this
dialog.setPositiveButton("Take me to location services", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
Intent locationSettingIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(locationSettingIntent, ACTION_LOCATION_SETTING);
}
});
Now when you return from the location setting, you'll get a callback here.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case ACTION_LOCATION_SETTING:
if (resultCode == Activity.RESULT_OK) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) {
//DO FANCY STUFF WITH LOCATION
}
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
Simple!
Related
I have an Activity which makes use of KeyguardManager.
The intention is to disallow the user to use the app, if they are unable to successfully supply their credentials.
Though the keyguard intent appears at the start of the app, pressing the device back button moves the intent away, showing the activity which started it.
Overriding the onBackPressed does not seem to help, as it isn't associated with the intent.
#Override
public void onBackPressed() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
KeyguardManager km = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
if (km.isKeyguardSecure()) {
setShowWhenLocked(true);
Intent i = km.createConfirmDeviceCredentialIntent("Authentication required", "password");
startActivityForResult(i, CODE_AUTHENTICATION_VERIFICATION);
}
}
What if you use finish() after startActivity() ?
EDIT:
Add finish() on your onActivityResult() if the pattern is false.
What you want to achieve can be done using a "Staging" Activity. For example, you can have a LoginActivity that will check if the user is authenticate or not then from there decide where to redirect him.
The LoginActivity should look something like this, of course you need to adapt it to your business logic :
public class LoginActivity extends AppCompatActivity {
private static final int CODE_AUTHENTICATION_VERIFICATION = 24;
private boolean isFirstLaunch = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
isFirstLaunch = false;
//startActivityForResult With your intent to authenticate the user
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CODE_AUTHENTICATION_VERIFICATION){
Log.i("LOGIN", "return from key guard");
//Check the data and decide if you redirect the user to main activity or not
}
}
#Override
protected void onResume() {
super.onResume();
if(!isFirstLaunch){
Log.i("LOGIN", "resume not first launch");
// the user tried to cancel the authentication either present him with the authentication process again or finish() the activity
}
}
}
Please, N/B: Overriding the onBackPressed does help only when you create a conditional statement controlled by a boolean variable in the onBackPressed method and call it in the onActivityResult i.e when the resultCode != RESULT_OK. Another option is to exit the app when resultCode != RESULT_OK (moveTaskToBack(true)) Here is what I mean below:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == INTENT_AUTHENTICATE) {
if (resultCode == RESULT_OK) {
//do something you want when pass the security
} else //resultCode != RESULT_OK
//Option 1 Ensure you override onBackPressed() with a conditional
//statement controlled by a boolean variable.
onBackPressed();
//Option 2
moveTaskToBack(true); //Exit app when a user click the back button.
}
}
I have a weird bug that is driving me crazy. I'm working on Android Marshmallow and I'm implementing the new permissions. When I click my Login button, I check to see if the user has gps permissions. If not, I request them. The way the code works is that after permissions are asked, an Async task is called to get some settings from a REST service, then on the onPostExecute of the Async task, it will fire an Intent.
When the user Allows permissions, everything works fine. If the user denies permissions, it will call the Async task and call the Intent, but it will not activate the Intent. It simply stays on the screen.
The Button Click
Button btnLogin = (Button) findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
int has_permission = 0;
if (Build.VERSION.SDK_INT >= 23)
{
has_permission = Check_Permission(Manifest.permission.ACCESS_FINE_LOCATION);
}
action = "login";
if(has_permission == 0)
{
Get_Location();
load_system_settings_async = new Load_System_Settings_Async();
load_system_settings_async.execute((Void) null);
}
}
});
Check Permission Code
protected int Check_Permission(final String permission)
{
int has_permission = checkSelfPermission(permission);
if (has_permission != PackageManager.PERMISSION_GRANTED)
{
if (!shouldShowRequestPermissionRationale(permission) && (request_times > 0))
{
String title="";
if(permission.equals(Manifest.permission.ACCESS_FINE_LOCATION))
{
title = "You need to allow GPS access";
}
else if(permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE))
{
title = "You need to allow storage access";
}
else if(permission.equals(Manifest.permission.CALL_PHONE))
{
title = "You need to allow access phone access";
}
Show_Alert_Dialog("Ok", title,
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", getPackageName(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
//requestPermissions(new String[] {permission}, REQUEST_CODE_ASK_PERMISSIONS);
}
});
return has_permission;
}
requestPermissions(new String[] {permission}, REQUEST_CODE_ASK_PERMISSIONS);
request_times++;
return has_permission;
}
return has_permission;
}
Permission Request
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults)
{
if (requestCode == 123)
{
if(grantResults[0] == 0)
{
Get_Location();
}
load_system_settings_async = new Load_System_Settings_Async();
load_system_settings_async.execute((Void) null);
//request_times = 0;
}
else
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
it seems like the problem is when user denied the permission ,control fall in onRequestPermissionsResult where you are executing your asynch task even if the permission is not granted .check comment in following code
public void onRequestPermissionsResult(int requestCode, #NonNull String[]
permissions, #NonNull int[] grantResults)
{
if (requestCode == 123) // yes request code is the same go on
{
if(grantResults[0] == 0) //yes we get the approval
{
Get_Location();
}
// oh even if we didn't get the approval we still gonna execute the task
load_system_settings_async = new Load_System_Settings_Async();
load_system_settings_async.execute((Void) null);
//request_times = 0;
}
else //control only come here when request code will not match
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
you need to combine the if condition like this
if (requestCode == 123 && grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Ok, I figured it out .. When I was passing a custom Object with putExtra in the Intent, there was a property that was null, so when it was executing writeToParcel in the object, it was crashing. Unfortunately, Android kept executing with out crashing .. it just did nothing. I simply added a setter to the object and set the value to false. Issue had nothing to do with the Permission code. Four hours of life and sleep lost that I will not get back. Thanks all for who viewed.
I need to build an app which will recognize QR codes without forcing the user to install other apps. In future, I will also need to manipulate the scanned image before recognizing the code (codes scanned by me will have inverted colors).
Trying to follow hints and tutorials from these links:
Integrating the ZXing library directly into my Android application
Embedding ZXing in android app
http://karanbalkar.com/2013/12/tutorial-65-implement-barcode-scanner-using-zxing-in-android/
After creating some basic code and running the app I click my Scan button and get an error that No Activity found to handle Intent { act=com.google.zxing.client.android.SCAN (has extras) }
What I've done:
Create new project
Copy core-3.2.1.jar to libs/
Add intent calling and result handling
intent/result code added by me:
private Button scan;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scan= (Button)findViewById(R.id.btnScan);
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
startActivityForResult(intent, 0);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == 0) {
if (resultCode == RESULT_OK) {
String contents = intent.getStringExtra("SCAN_RESULT");
String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
// Handle successful scan
MultiFormatWriter writer = new MultiFormatWriter();
} else if (resultCode == RESULT_CANCELED) {
// Handle cancel
Log.i("App","Scan unsuccessful");
}
}
}
How to start the intent? What am I doing wrong?
you should launch scan like this:
#Override
public void onClick(View v) {
IntentIntegrator integrator = new IntentIntegrator(MainActivity.this);
integrator.setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES);
//in case you want to customize a bit.
integrator.setPrompt("Scan a QR/Bar code");
integrator.setCameraId(0);
integrator.setBeepEnabled(false);
integrator.initiateScan();
}
Receive results like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE: {
if (resultCode != RESULT_CANCELED) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
String data = scanResult.getContents();
// use this data
} else {
// error
}
break;
}
}
}
Edit 1:
Add this to build.gradle of your app as dependencies:
compile 'com.journeyapps:zxing-android-embedded:3.0.2#aar'
compile 'com.google.zxing:core:3.2.0'
Try the below link it worked for me:
https://github.com/dlazaro66/QRCodeReaderView
Android Developer Documentation gives this example of requesting permissions at runtime:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
What is "MY_PERMISSIONS_REQUEST_READ_CONTACTS" in this example? It says it's an app-defined int constant, but does that mean I should make a Constants.java and declare a public static int? What should the value be?
In other examples I see people use 1 here, or 0 or 0xFFEEDDCC, but I can't find an explanation of what it is. Can someone explain to me what needs to go here and why? (In my case, I need to make sure the app has permission to access fine location)
The ActivityCompat documentation says "Application specific request code to match with a result reported to onRequestPermissionsResult"? This does not help me.
What is "MY_PERMISSIONS_REQUEST_READ_CONTACTS" in this example?
It is an int, to tie a particular requestPermissions() call to the corresponding onRequestPermissionsResult() callback.
Under the covers, requestPermissions() uses startActivityForResult(); this int serves the same role as it does in startActivityForResult().
does that mean I should make a Constants.java and declare a public static int?
I would just make it a private static final int in the activity. But, you can declare it wherever you want.
What should the value be?
I seem to recall that it needs to be below 0x8000000, but otherwise it can be whatever you want. The value that you use for each requestPermissions() call in an activity should get a distinct int, but the actual numbers do not matter.
If your activity has only one requestPermissions() call, then the int value really does not matter. But many apps will have several requestPermissions() calls in an activity. In that case, the developer may need to know, in onRequestPermissionsResult(), what request this is the result for.
Look just a little further down in the documentation under "Handle the permissions request response" and you will see its purpose.
A callback method called onRequestPermissionsResult gets sent back the same code as a parameter so you know which permission was being requested/granted:
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Since the constant is used by you only you can give it whatever value you like as a public static final int. Each permission being requested needs its own constant.
I went through all answers, but doesn't satisfied my exact needed answer, so here is an example that I wrote and perfectly works, even user clicks the Don't ask again checkbox.
Create a method that will be called when you want to ask for runtime permission like readContacts() or you can also have openCamera() as shown below:
private void readContacts() {
if (!askContactsPermission()) {
return;
} else {
queryContacts();
} }
Now we need to make askContactsPermission(), you can also name it as askCameraPermission() or whatever permission you are going to ask.
private boolean askContactsPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
Snackbar.make(parentLayout, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
}).show();
} else if (contactPermissionNotGiven) {
openPermissionSettingDialog();
} else {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
contactPermissionNotGiven = true;
}
return false;
}
Before writing this function make sure you have defined the below instance variable as shown:
private View parentLayout;
private boolean contactPermissionNotGiven;;
/**
* Id to identity READ_CONTACTS permission request.
*/
private static final int REQUEST_READ_CONTACTS = 0;
Now final step to override the onRequestPermissionsResult method as shown below:
/**
* Callback received when a permissions request has been completed.
*/
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_CONTACTS) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
queryContacts();
}
}
}
Here we are done with the RunTime permissions, the addon is the openPermissionSettingDialog() which simply open the Setting screen if user have permanently disable the permission by clicking Don't ask again checkbox. below is the method:
private void openPermissionSettingDialog() {
String message = getString(R.string.message_permission_disabled);
AlertDialog alertDialog =
new AlertDialog.Builder(MainActivity.this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
.setMessage(message)
.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
dialog.cancel();
}
}).show();
alertDialog.setCanceledOnTouchOutside(true);
}
What we missed ?
1. Defining the used strings in strings.xml
<string name="permission_rationale">"Contacts permissions are needed to display Contacts."</string>
<string name="message_permission_disabled">You have disabled the permissions permanently,
To enable the permissions please go to Settings -> Permissions and enable the required Permissions,
pressing OK you will be navigated to Settings screen</string>
Initializing the parentLayout variable inside onCreate method
parentLayout = findViewById(R.id.content);
Defining the required permission in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
The queryContacts method, based on your need or the runtime permission you can call your method before which the permission was needed. in my case I simply use the loader to fetch the contact as shown below:
private void queryContacts() {
getLoaderManager().initLoader(0, null, this);}
This works great happy coding :)
public class SplashActivity extends RuntimePermissionsActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
SplashActivity.super.requestAppPermissions(new
String[]{android.Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE}, R.string.app_name
, 20);
}
#Override
public void onPermissionsGranted(int requestCode) {
try {
TelephonyManager tele = (TelephonyManager) getApplicationContext()
.getSystemService(Context.TELEPHONY_SERVICE);
String imei =tele.getDeviceId()
} catch (Exception e) {
e.printStackTrace();
}
}
public abstract class RuntimePermissionsActivity extends AppCompatActivity {
private SparseIntArray mErrorString;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mErrorString = new SparseIntArray();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
for (int permission : grantResults) {
permissionCheck = permissionCheck + permission;
}
if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) {
onPermissionsGranted(requestCode);
} else {
finish();
}
}
public void requestAppPermissions(final String[] requestedPermissions,
final int stringId, final int requestCode) {
mErrorString.put(requestCode, stringId);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
boolean shouldShowRequestPermissionRationale = false;
for (String permission : requestedPermissions) {
permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
}
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale) {
ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
/*Snackbar.make(findViewById(android.R.id.content), stringId,
Snackbar.LENGTH_INDEFINITE).setAction("GRANT",
new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
}
}).show();*/
} else {
ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
}
} else {
onPermissionsGranted(requestCode);
}
}
public abstract void onPermissionsGranted(int requestCode);
}
I am working on restoring SMS on KITKAT. Referring to this article I have added the things which are required to set my app as default app for SMS. After adding all required things in manifest file I have write the following code:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
mDefaultSmsApp = Telephony.Sms.getDefaultSmsPackage(mContext);
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, mContext.getPackageName());
mContext.startActivity(intent);
}
The above code shows this dialog but I am unable to get the result from this activity/dialog either user clicked on Yes or No because I want to add listener or get any code which should represent that the user clicked on these buttons.
Thanks.
One way to do this is to fire the Intent with startActivityForResult(), and then check the resultCode in the onActivityResult() method. Please note that I've changed the code in the example to run in an Activity's Context.
private static final int DEF_SMS_REQ = 0;
private String mDefaultSmsApp;
...
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
mDefaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this);
if (!getPackageName().equals(mDefaultSmsApp))
{
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getPackageName());
startActivityForResult(intent, DEF_SMS_REQ);
}
}
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case DEF_SMS_REQ:
boolean isDefault = resultCode == Activity.RESULT_OK;
...
}
}
As mentioned in a comment below, apparently checking the result code is not 100% reliable. A safer check is to simply compare your app's package name to the current default in onActivityResult(). There's no need to check the result code at all, like the answer linked in the comment shows.
String currentDefault = Sms.getDefaultSmsPackage(this);
boolean isDefault = getPackageName().equals(currentDefault);
The way you can react on "yes" button click:
private String mDefSmsPackage;
#Override
public void onCreate(#Nullable Bundle state) {
//...
mDefSmsPackage = Telephony.Sms.getDefaultSmsPackage(getActivity())
}
#Override
public void onResume() {
super.onResume();
String newDefSmsPkg = Telephony.Sms.getDefaultSmsPackage(getActivity());
if (!TextUtils.equals(mDefSmsPackage, newDefSmsPkg)) {
mDefSmsPackage = newDefSmsPkg;
//ON DEF SMS APP CAHNGE...
}
}