Instructions called before the activity is closed - java

I'm trying to understand if the user has enabled the admin or not and LATER update a checkbox (in onResume).
The problem is that the activity which allows the user to enable the admin is launched and it's launched the following code without waiting for the user decision.
How could bypass it?
private void doAttivaRimuoviAdmin() {
if (isAdminAttivo()) {
mDPM.removeActiveAdmin(mDeviceAdminSample);
} else {
Intent localIntent = new Intent("android.app.action.ADD_DEVICE_ADMIN");
localIntent.putExtra("android.app.extra.DEVICE_ADMIN", mDeviceAdminSample);
localIntent.putExtra("android.app.extra.ADD_EXPLANATION",
getString(R.string.spiegazione_amministratore));
startActivityForResult(localIntent, 1);
// se non รจ stato dato il permesso, non attiva la checkbox
Editor e = mPrefs.edit();
if (isAdminAttivo()) {
e.putBoolean("spegnischermoabilitato", true);
} else {
e.putBoolean("spegnischermoabilitato", false);
}
e.commit();
Log.i(getString(R.string.app_name), ""+ mPrefs.getBoolean("spegnischermoabilitato", false));
}
}
In poor words, the sharedpreference "spegnischermoabilitato" always has FALSE within it.

From the documentation of startActivityForResult():
Launch an activity for which you would like a result when it finished.
When this activity exits, your onActivityResult() method will be
called with the given requestCode. Using a negative requestCode is the
same as calling startActivity(Intent) (the activity is not launched as
a sub-activity).
In other words, you will need to override onActivityResult(). In this method you will then have to check that the method is called with the requestCode you set in startActivityForResult(), and also that it contains the expected resultCode. If it does write your preference.

Related

Save Application Wide Boolean in SharedPreference

I know that this is a common question asked, and I have spent all afternoon trying different solutions that don't seem to work.
I am trying to store a boolean receiveNotifications in SharedPreferences but when I send a notification it still comes through. When I check whether the boolean is set in the activity I set it in, it says that the value is what it should be, but when I call this in my Firebase MessagingService it still allows the notification to come through.
This is my first time using them so if you see the obvious answer thats why.
Storing the Boolean:
// shared preferences
notificationsPref = mContext.getSharedPreferences("notifications", MODE_PRIVATE);
SharedPreferences.Editor editor = notificationsPref.edit();
editor.putBoolean("receiveNotifications", false);
editor.apply();
Checking if Boolean is Set:
// check if they want to receive notifications
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("notifications", MODE_PRIVATE);
Boolean areNotificationsAllowed = sharedPreferences.getBoolean("receiveNotifications", true);
if (areNotificationsAllowed){
Toast.makeText(this, "Send Notification", Toast.LENGTH_SHORT).show();
sendNotification(contentTitle, messageBody);
}
A push message is a Json object, next example is directly from the docs:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
There are 3 types of push messages, notification, data, and both;
//Notification
"message":{
"notification":{
}
}
//data
"message":{
"data":{
}
}
//both
"message":{
"notification":{
},
"data":{
}
}
Each will trigger a different behavior in the app depending if the app is open or not.
Notification: if the app is open the code on the service will be executed, if not the notification is showed by default
Data: Always the code on the service will be executed
Both: f the app is open the code on the service will be executed, if not the notification is showed by default and the data will be available in the launcher activity as extra obtainable from the intent
The Firebase web console will always send "notification" type and if you add data as custom params it will send both.
Your boolean will never be taken in consideration if the app is closed and the notification comes from the web console.
Turns out that no matter what you do Firebase must override whatever you have set in the application. I found this out by instead of sending from the Firebase console, I sent notification from my web server. The notification was stopped perfectly and the Shared Preference worked.
private SharedPreferences prefs;
private SharedPreferences.Editor editor;
prefs = getApplicationContext().getSharedPreferences("notifiactions",
MODE_PRIVATE);
editor = prefs.edit();
/////Assigning a Boolean///////////
editor.putBoolean("receiveNotifications", false);
editor.commit();
//Retrieving Boolean
prefs = getApplicationContext().getSharedPreferences("notifications",
MODE_PRIVATE);
bool = prefs.getBoolean("receiveNotifications", true);
//Try replacing this with your code also
if(bool){
}

Disable first launch activity

I've implemented a library from github in my app. I want to know how to disable it after its first launch. I dont want it to be shown each time on app launch. heres what i've tried. I tried adding a boolean variable but it didnt work.
This question isn't just for this topic, suppose i want to call a method ONLY AFTER FIRST TIME after app install, I dont want it to be called again once its called in first app launch time. i hope it's clear what i'm trying to achieve.
boolean firstLoad;
if(firstLoad=true) {
TapTargetView.showFor(this, // `this` is an Activity
TapTarget.forView(findViewById(R.id.button), "This is a target", "We have the best targets, believe me")
// All options below are optional
.outerCircleColor(R.color.colorPrimary) // Specify a color for the outer circle
.outerCircleAlpha(0.96f) // Specify the alpha amount for the outer circle
.targetCircleColor(R.color.colorAccent2) // Specify a color for the target circle
.titleTextSize(20) // Specify the size (in sp) of the title text
.titleTextColor(R.color.colorAccent2) // Specify the color of the title text
new TapTargetView.Listener() { // The listener can listen for regular clicks, long clicks or cancels
#Override
public void onTargetClick(TapTargetView view) {
super.onTargetClick(view); // This call is optional
}
});
}
firstLoad=false;
Boolean firstLoad = getSharedPreferences("PREFERENCE", MODE_PRIVATE)
.getBoolean("firstLoad", true);
if (firstLoad) {
//call your method
getSharedPreferences("PREFERENCE", MODE_PRIVATE).edit().putBoolean("firstLoad", false).commit();
}

Unable to fetch SharedPreferences

I'm trying to get familiar with using SharedPreferences, by building a simple test app where I store and retrieve user preferences by using a class that extends 'PreferenceActivity'.
The problem is that every time I shut down the app and start it again I'm unable to load the SharedPreferences values that I earlier selected.
In the MainActivity's onCreate method I am first calling a method 'loadPreferences', then creating an ImageView and a button.
I assigned onclick listener to the button that creates and starts a new intent.
...onClick(View v){
Intent intent = new Intent(MainActivity.this, MyPrefsActivity.class);
startActivity(intent);
}
In MyPrefsActivity class I have a ListPreference that has a 'Preference.OnPreferenceChangeListener'.
... {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
imageNumber = Integer.parseInt(newValue.toString());
return true;
}
};
Upon return from MyPrefsActivity to MainActivity in the 'onResume':
protected void onResume() {
super.onResume();
savePreferences();
loadPreferences();
}
private void savePreferences(){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("imageNumber", MyPrefsActivity.imageNumber);
editor.apply();
}
private void loadPreferences (){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int imageNumb = prefs.getInt("imageNumber", 0);
switch (imageNumb){
case 0:
imageView.setImageResource(R.mipmap.image1);
break;
case 1:
imageView.setImageResource(R.mipmap.image2);
break;
case 2:
imageView.setImageResource(R.mipmap.image3);
break;
default:
imageView.setImageResource(R.mipmap.image4);
}
}
When 'loadPreferences' is called for the first time upon startup, 'imageNumb' allways has a value 0, instaed of the value that I assigned to on previous run in method 'savePreferences'.
I noticed that after startup when I enter 'MyPreferencesAction' for the first time and open the ListPreferences, the checkbox that I selected on the last run is already selected for me. It seems like my selection is saved but when I try to load SharedPreferences am I messing up something???
You have to save your preferences in onPause event. Right now you are saving it in onResume when values you want are no longer there.
#Override
protected void onPause(){
super.onPause();
savePreferences();
}
#Override
protected void onResume() {
super.onResume();
loadPreferences();
}
There is another issue with your code. You are saving preferences in MainActivity, but you are changing them in MyPrefsActivity. That will not work. You have to save changes to the preferences in MyPrefsActivity, use above load/save pattern in there too. If you don't have any preference changes happening in MainActivity, you can safely omit calling savePreferences from it.
Depending on MyPrefsActivity declaration calling MyPrefsActivity.imageNumber from MainActivity may not be safe, you will have to change that code too. Like I said, most likely you don't need it at all in MainActivity (if you saving are only preferences values that are set in MyPrefsActivity) and that should be part of MyPrefsActivity.
Also Preference.OnPreferenceChangeListener is probably redundant since it's main usage is to be invoked when the value of this Preference has been changed by the user and is about to be set and/or persisted. This gives the client a chance to prevent setting and/or persisting the value.
I realized there was a lot of needless complexity in my code. So I got completely rid of the method savePreferences(). Instead i simplified the PreferenceChangeListeners method onPreferenceChange(...):
This seems to me to be the most simplest way to update SharedPreferences when using PreferenceActivity.
public boolean onPreferenceChange(Preference preference, Object newValue) {
preference.getEditor().
putInt("imageNumber", Integer.parseInt(newValue.toString())).apply();
return true;
}
Now I save the SharedPreferences manually, only when 'onPreferenceChange' is called. Not on 'onResume', 'onStop', 'onRestart' or on 'onPause'.
Please inform me if this is a bad way to change SharedPreferences.
Quoting Dalija Prasnikar: "reference.OnPreferenceChangeListener is probably redundant since it's main usage is to be invoked when the value of this Preference has been changed by the user and is about to be set and/or persisted. This gives the client a chance to prevent setting and/or persisting the value."
If you understood you correctly Dalija, there is a 'onPreferenceChange(...)' like method that does the job but does not have a boolean return value but void? I was not able to find any examples, could you please show or point to an examle?

How should I store user credentials so that users don't have to login again?

I have 2 activities: Login and Main
I also have App class that runs before the Activities.
public class App extends Application
{
#Override
public void onCreate()
{
super.onCreate();
}
}
My AndroidManifest.xml makes Login Activity be the first activity to run.
Should I go to the Login activity, check the SharedPreferences then determine if user has already logged in?
Or Should I make a blank Activity that does this check then launches the correct Activity, either Login or Main?
Or Maybe the check should be done in the App class and a change made to the Android Manifest.
So that this doesn't become an opinion fest, any suggestion has to have a logical reason behind it and why it would be best.
Good solution is create new class for holding information about session, e.g.:
public class SessionManager {
// Shared Preferences
SharedPreferences pref;
// Editor
Editor editor;
// Context
Context mContext;
// Shared pref mode
int PRIVATE_MODE = 0;
// Sharedpref file name
private static final String PREF_NAME = "MyPref";
// All Shared Preferences Keys
private static final String IS_LOGIN = "IsLoggedIn";
private static final String KEY_EMAIL = "email";
private static final String KEY_ID = "id";
// Constructor
public SessionManager(Context context) {
this.mContext = context;
pref = mContext.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
editor = pref.edit();
}
/**
* Create login session
*/
public void createLoginSession(String email, int id) {
// Storing login value as TRUE
editor.putBoolean(IS_LOGIN, true);
// Storing email in pref
editor.putString(KEY_EMAIL, email);
// Storing id in pref
editor.putInt(KEY_ID, id);
// commit changes
editor.commit();
}
/**
* Check login method wil check user login status
* If false it will redirect user to login page
* Else won't do anything
*/
public void checkLogin() {
// Check login status
if (!this.isLoggedIn()) {
// user is not logged in redirect him to Login Activity
Intent i = new Intent(mContext, LoginActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Staring Login Activity
mContext.startActivity(i);
}
}
/**
* Quick check for login
* *
*/
// Get Login State
public boolean isLoggedIn() {
return pref.getBoolean(IS_LOGIN, false);
}
public int getId() {
return pref.getInt(KEY_ID, 0);
}
}
And in your MainActivity you have to check if user is logged in or not:
public class MainActivity extends Activity {
// Session Manager Class
SessionManager session;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Session class instance
session = new SessionManager(getApplicationContext());
session.checkLogin();
.
// code goes here
...
If user is not logged in he will be redirected to LoginActivity.
In LoginActivity just check email/pass or whatever,... call:
session.createLoginSession(mEmail, mId);
and redirect user back to MainActivity
Saving credentials its up on you. Ofc its better to keep it in safe place and encoded ; )
There are many possible solutions:
1) Splashscreen
Theoretically we should not use splash screens :P
But in this case it will be super easy ;)
Intent mIntentMain = ...
Intent mIntentLogin = ...
boolean mIsUserLogged = ...
startActvity(mIsUserLogged ? mIntentMain : mIntentLogin);
2) Main Activity
Start main activity, and before filling the screen with data, ws calls etc, just after the onCreate, check credentials ;) if its
ok -> start parsing data / filling stuff
else -> finish main activity, show toast, open login activity
3) Fragments
Activity Main -> check credentials -> put login fragment or main fragment
Check for login in SharedPreferences takes a little time and if you implement this check via blank activity the launch time of your app will be increased without a reason (time for launch 2 activities instead of 1 activity)
you can do check in your MainActivity and if it fails then run LoginActivity
How are you handling signups? The whole login/signup/authentication flow, while seemingly easy on paper, can get pretty complex with lots of edge cases when you take into account multiple simultaneous logins, password changes, forgotten passwords, account deletions etc. That said, Android provides AccountManager designed specifically for this purpose and this is one of the better tutorials on how to use it.
You can view splash screen while loading the application and in that time to check the user name and password.
Or you can upload the main screen with charging indicator to the user knew something was going on and the application not stuck.
First approach:
I would suggest you to go with Fragments.
Launch MainActivity , check inside onCreate() whether the user's login session is valid, if it is valid go with your normal workflow, otherwise launch your LoginFragment
Second approach:
Go with a SplashActivity , check your login user session validity and decide the workflow
Third approach
Assume that user is logged in, and launch your MainActivity inside onCreate() check your users session validity , if invalid then launch LoginActivity and finish() your MainActivity
Undoubtly First one can be your best choice , but I should leave this decision to you. :)

The method getPreferenceManager() is undefined for the type BatteryService in android app

I am making a service so I have service class which is extended from Service. I am getting a checkbox from PreferenceScreen and based on whether it is checked or not I perform an action. To get CheckBoxPreference I use getPreferenceManager() method. But it has red underline. When I hover over it shows me this error The method getPreferenceManager() is undefined for the type BatteryService. When I use the same code in my main class then it works. Here is my code
public int onStartCommand(Intent intent, int flags, int startId) {
initNotification();
final CheckBoxPreference checkboxPref = (CheckBoxPreference) getPreferenceManager().findPreference("cbAlarm");
checkboxPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference,
Object newValue) {
if (newValue.toString().equals("true")) {
Toast.makeText(getApplicationContext(), "Service Started", Toast.LENGTH_LONG).show();
registerReceiver(batteryInfoReceiver, new IntentFilter(
Intent.ACTION_BATTERY_CHANGED));
} else if (newValue.toString().equals("false")) {
stopService(new Intent(getBaseContext(),
BatteryService.class));
Toast.makeText(getApplicationContext(),
"Unchecked", Toast.LENGTH_SHORT).show();
}
return true;
}
});
return START_STICKY;
}
How can I solve this problem? Help Please
The getPreferencesManager() function is not available on Service derived objects - only on PreferenceActivity or PreferenceFragment derived objects where you likely copied the above code from, or individual Preference objects.
If you only wanted to sample the value of the checkbox preference when your service starts, use something like:
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
boolean alarm = sp.getBoolean("cbAlarm", false); // defaulting to false
However, I'm guessing from your Listener code that you also want to be notified if the user changes the setting. That would mean keeping onPreferenceChange in the PreferenceActivity/PreferenceFragment, and sending the service a message. For that, consider something like Android best way to communicate from an Activity to a Service / Engine, or simply start/stop the whole service if it has nothing to do when the Alarm is off!

Categories