android getDrawable() doesn't run - android

I am trying to make an app to turn on mobile data on click. However, it requires to detect if mobile data is already on. If it is already on, data1.png is displayed else data0.png. However, for some reason it is not changing. TEST 2 is running though. (wdata is Image Button) This is the code:
ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
try {
Class cmClass = Class.forName(cm.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); // Make the method callable
// get the setting for "mobile data"
mobEnabled = (Boolean)method.invoke(cm);
} catch (Exception e) {
// Some problem accessible private API
// TODO do whatever error handling you want here
}
Toast.makeText(MainActivity.this, ""+mobEnabled, Toast.LENGTH_SHORT).show();
IF MOBILE DATA IS ENABLED, IT RETURNS TRUE.
if(mobEnabled){
wdata1=getResources().getDrawable(R.drawable.data1);
Toast.makeText(MainActivity.this, ":Test 1:"+mobEnabled, Toast.LENGTH_SHORT).show(); //RUNS
wdata.setImageDrawable(wdata1);// DOESN'T SET
}else{
wdata1 =
getResources().getDrawable(R.drawable.data0);
Toast.makeText(MainActivity.this, ":Test 2:"+mobEnabled, Toast.LENGTH_SHORT).show();
wdata.setImageDrawable(wdata1);
}
I have used the Drawable wdata1 in other areas:
wdata.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mobileDataEnabled(getApplicationContext())){
setMobileDataEnabled(getApplicationContext(), false);
wdata1 =
getResources().getDrawable(R.drawable.data0);
amobileDataEnabled = false;
}else{
setMobileDataEnabled(getApplicationContext(),true);
wdata1 =
getResources().getDrawable(R.drawable.data1);
amobileDataEnabled = true;
}
wdata.setImageDrawable(wdata1);
}
});
And in the onResume() method:
if( amobileDataEnabled){
wdata1 =
getResources().getDrawable(R.drawable.data1);
wdata.setImageDrawable(wdata1);
}else {
wdata1 =
getResources().getDrawable(R.drawable.data0);
wdata.setImageDrawable(wdata1);
}

After setting a drawable to something else, try calling wdata.invalidateDrawable(wdata1); right afterwards to indicate it needs to be refreshed.

Related

Settings.canDrawOverlays is returning false even after turning the permission on from settings

I am trying billow Code from this answer to check if the permission is enabled. but it is returning false even when the permission is enabled from the settings.
public static boolean canDrawOverlayViews(Context con){
if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;}
try {
return Settings.canDrawOverlays(con);
}
catch(NoSuchMethodError e){
return canDrawOverlaysUsingReflection(con);
}
}
public static boolean canDrawOverlaysUsingReflection(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });
return AppOpsManager.MODE_ALLOWED == mode;
} catch (Exception e) { return false; }
}
Recently I've also faced the same issue and got the following workaround .
Referenced from
https://code.google.com/p/android/issues/detail?id=198671#c7
public boolean getWindoOverLayAddedOrNot2() {
String sClassName = "android.provider.Settings";
try {
Class classToInvestigate = Class.forName(sClassName);
if (context == null)
context = activity;
Method method = classToInvestigate.getDeclaredMethod("isCallingPackageAllowedToDrawOverlays", Context.class, int.class, String.class, boolean.class);
Object value = method.invoke(null, context, Process.myUid(), context.getPackageName(), false);
Log.i("Tag", value.toString());
// Dynamically do stuff with this class
// List constructors, fields, methods, etc.
} catch (ClassNotFoundException e) {
// Class not found!
} catch (Exception e) {
// Unknown exception
e.printStackTrace();
}
return false;
}
does the check involves the device admin?
I have encountered this problem when disabling device admin, I have checked this permission in the DeviceAdminReceiver->onDisabled() and on some devices, and canDrawOverlays returned false, despite the fact i had the permission.
The above answer helped sometimes but not all the time. the thing that did work is Thread.sleep before the check.
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// some exception here
}
The minimal time that worked for me was 20 millis. than canDrawOverlays returned true
Note: this is not a good practice however this is the only thing that worked for me
Based on BennyP's answer, I've made a Runnable run the required code after 500ms and that worked very well. The feedback is a bit delayed, but the user won't even notice the delay.
This is the code I've added to my onResume()
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(!Settings.canDrawOverlays(ControllerActivity.this)){
//Handle overlay permission not given here
}
else{
//Handle overlay permission given here
}
}
}, 500);
Hope it helps!
I tried restarting the activity after the user accessed the setting . This is code :
public static void restartActivity(Activity act){
Intent intent = getIntent();
finish();
startActivity(intent);
}
First of all, I am really very surprised with this strange behaviour of
Settings.canDrawOverlays(this);
I also faced the same issue with its usage, it was returning false even if the permission is already assigned.
What I noticed that, I was using this check in my onStart() method, where it was creating this wired behavior. To resolve this, I searched over internet and no result was there that can satisfy me and the one I can use.
Solution
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.e("Overlay Permission", "" + Settings.canDrawOverlays(this));
if (!Settings.canDrawOverlays(this)) {
MyPreferences.saveBoolean(HomeScreen.this, "showOverlayPermissionDialog", true);
} else {
MyPreferences.saveBoolean(HomeScreen.this, "showOverlayPermissionDialog", false);
}
}
I did something lake this, in my onCreate(). Here I saved the values accordingly in my SharedPreferences, and according to these Shared Preference values, I created a check for showing an overlay dialog in my onStart(). This worked fine!
You can try this solution, and mark this answer useful if your problem is solved.
Thanks

Run Service only when on Wifi if user wants to

I made an app whos purpose is to download and set wallpaper in set intervals.
User can choose to do that only when connected to wifi or not.
Relevant code:
mWallpaperButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mSwitchWifi.isChecked()) {
mConnectivity = mConnectionDetector.isConnectedToWifi();
} else {
mConnectivity = mConnectionDetector.isConnectedToInternet();
}
if (mConnectivity) {
my code here
}
The code above works fine for setting the wallpaper the first time.
My problem is, I need the Service to check if the user wants to update wallpaper only over WIFI before doing so. At the moment, wallpaper is updated regardless of mSwitchWifi state. (which is bad, because it can use mobile data and user sometimes doesn't want that.)
I tried running similar Switch code in Service but I can't because it must be called in a UI Thread.
I also tried couple of workarounds and Intent.putExtra but I get exception:
NullPointerException: Attempt to invoke virtual method on a null object reference
Any idea how to check network state in service?
My service code atm:
public static class Service extends IntentService {
public Service() {
super("wallpaperchanger-download");
}
#Override
protected void onHandleIntent(Intent intent) {
if (url == null) {
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
String getUrl = sharedPreferences.getString(pref_urlKey, null);
if (getUrl != null) {
url = getUrl;
}
}
wm = WallpaperManager.getInstance(this);
try {
InputStream input = new URL(url).openStream();
Log.v(TAG, url);
wm.setStream(input);
input.close();
} catch (Exception e) {
e.printStackTrace();
}
loading = false;
Log.v(TAG, "Service Running Url " + url);
}
}
If you question is how to access the user selection inside a service/runnable/thread then you can use shared preferences to achieve this. So in your case when the user selects the choice for the first time you want to do something like this:
if(mSwitchWifi.isChecked()) { // i guess this is no wifi
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Editor editor = sharedPeredences.edit()
editor.putBoolean("isWifi", false)
} else { // guessing this is wifi
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Editor editor = sharedPeredences.edit()
editor.putBoolean("isWifi", true)
}
This is this code to check if it is true or false:
mWallpaperButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Boolean isWifi = isWifi()
if (!isWifi) { // i guess this is if not wifi
mConnectivity = mConnectionDetector.isConnectedToWifi();
} else if (isWifi) { // guessing this is wifi
mConnectivity = mConnectionDetector.isConnectedToInternet();
}
}
}
public Boolean isWifi() { // you can call this inside your service
SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
Boolean wifiState = sharedPreferences.getBoolean("isWifi", true)
return wifiState;
}
This is just a very rough implementation to give an idea of how you can do it, you can improve this many ways. For example you could put the if statement thats inside the onClickListener in the isWifi() function and just call isWifi() inside your runnable/thread...
you can set list preferences to auto update functions based on the network ....
You can create separate class to check the connectivity and from that class you can select the preferences like auto update only on wifi or when connected to network or do not auto update ....

Thread not terminating correctly, I think

public String newUser = "false";
public double lat = 0.0, lon = 0.0;
I have the following function in my android app (called when a Button is clicked) which starts a thread:
public void SignUpFunction(View view) {
assignValues();
String filledAll = checkIfFilled();
if (filledAll.equals("true")) {
Log.d("LIFECYCLE", "calling thread..");
//my thread
new validateThread().start();
Log.d("After thread start","This log call does not occur");
if (newUser.equals("true")) {
Toast.makeText(this, "Please wait as we obtain your location", Toast.LENGTH_SHORT).show();
getMyLocationFunction();
} else {
return;
}
}
}
validateThread:
class validateThread extends Thread {
public void run() {
Log.d("LIFECYCLE", "validateThread entered...");
try {
newUser = "true";
Log.d("validateThread", "Validated and found new user");
} catch (Exception e) {
Log.d("validateThread", "Exception in validateThread: " + e.getMessage());
}
}
}
The thread runs correctly...but after the last line, it does not go back to its point of start. I don't understand why this is happening because I've used threads before and they all work correctly.
I know I can just give the getMyLocation function inside the thread but I really need it this way.
I've searched for similar questions but none helped.. What am I doing wrong here?
Thanks in advance.
It's a race. SignUpFunction should wait until validateThread decides whether or not to set newUser = "true". Even with the race your code may work sometimes, but that is by accident.

How to disable Button while AsyncTask is running? (Android)

I am trying to disable a button while a download task is being executed. I have tried using setEnabled, setVisibility and setClickable. I think I tried all combinations of these options. All of them disable the button click events while the task is performing, but the events are still being registered somehow, and when I reactive the button, the handler is called if I clicked the button while it was disabled... even if it was invisible or "gone"! (not sure if it is called a handler, I want to refer to the onClick method).
I have also inserted a counter and a Log to verify what I've stated above. The code is shown below. This piece of code if(counter>1) return; is meant to stop the crash, but I would like to remove it, since I want to re-enable the button, and not disable it forever.
onClick:
public void downloadOnClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
//mButton.setVisibility(View.GONE);
mButton.setEnabled(false);
//mButton.setClickable(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
AsyncTask:
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
private HttpURLConnection mConnection;
#Override
protected String doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
mConnection = (HttpURLConnection) url.openConnection();
mConnection.setReadTimeout(10000 /* milliseconds */);
mConnection.setConnectTimeout(15000 /* milliseconds */);
mConnection.setRequestMethod("GET");
mConnection.setDoInput(true);
mConnection.connect();
int statusCode = mConnection.getResponseCode();
if (statusCode != HttpURLConnection.HTTP_OK) {
return "Error: Failed getting update notes";
}
return readTextFromServer(mConnection);
} catch (IOException e) {
return "Error: " + e.getMessage();
}
}
private String readTextFromServer(HttpURLConnection connection) throws IOException {
InputStreamReader stream = null;
try {
stream = new InputStreamReader(connection.getInputStream());
BufferedReader br = new BufferedReader(stream);
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line + "\n");
line = br.readLine();
}
return sb.toString();
} finally {
if (stream != null) {
stream.close();
}
}
}
#Override
protected void onPostExecute(String result) {
mTextView.setText(result);
// Can not reactivate button / cancel (pending?) events....
//mButton.setVisibility(View.VISIBLE);
mButton.setEnabled(true);
//mButton.setClickable(true);
}
}
The full project (it is very simple, just a training example) is available to test in this repository that I have just created.
To conclude, from what I have read, there is in fact a problem regarding button disabling. Mostly this is resolved through the use of a flag to call the onClick method only when the flag is true. Although, this does not solve the problem of re-enabling the button. I have also tried mButton.cancelPendingInputEvents(); but it does not work (and I do not know why. Click events are not yet registered? Or they are not pending?
Is there a simple solution to this problem? Any ideas? Am I missing some basic detail? If not, I am considering trying to create a new button programatically to contour the problem. If I do not keep references to old buttons, are they deleted through garbage collection?
Thanks in advance!
[Edit] Clarification:
Since the title could be misleading in this point, I want to clarify that I am able to disable and re-enable the button and all the functionality is ok except when the buttion is disabled. And note that I have added the line if(counter>1) return; just to test but it stops the button from working the way I wanted (that's why I am not using a flag. I don't want this line to be there when I solve the problem!). The log is enough to inform me that the method is being called when the button is re-enabled, because I clicked it when it was disabled!
I found that with your example, the AsyncTask was completing so fast that there was a very short amount of time that the Button was not clickable due to being disabled. So, it's basically a timing issue.
I found that by delaying the re-enabling of the Button by 4 seconds, it works as expected.
Note with this change that visually, the Button is re-enabled a split second after the TextView is populated.
Here is the code change in onPostExecute():
#Override
protected void onPostExecute(String result) {
mTextView.setText(result);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//re-enable the button
mButton.setEnabled(true);
}
}, 4000);
}
Note that you can remove the counter logic and it should work as expected now:
public void downloadOnClick(View v) {
Log.d(this.getLocalClassName(), "Button was clicked");
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
The error is here:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="#+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="downloadOnClick" />
You are missing the concept of OnClickListener! First of all, you have to modify the above xml in this way removing onClick attribute:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOWNLOAD TEXT"
android:id="#+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
Than you have to modify the Activity onCreate method in order to set the OnClickListener on your button:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
counter++;
Log.d(this.getLocalClassName(), "Button was clicked " + counter + " times.");
if(counter>1) return;
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mButton.setEnabled(false);
mTextView.setText("Getting html file...");
// if we use simple http, we will need to handle redirect status code
new DownloadWebpageTask().execute("https://www.google.com/");
} else {
mTextView.setText("No network connection available.");
}
}
});
}
This is the right way to handle a click.
See more:
Button | Android Developer
Moreover:
The best way from my point of view is implements the OnClickListener() on your Activity:
public class MyActivity extends Activity implements View.OnClickListener {
}
In this way you can write for each button where you need to set the OnClickListener do:
buttonX.setOnClickListener(this);
buttonY.setOnClickListener(this);
buttonZ.setOnClickListener(this);
In your Activity onClick() you must override the OnClickListener methods, so:
#Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonX)){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonY){
//do here what u wanna do.
} else if(v.getId() == R.id.ButtonZ){
//do here what u wanna do.
}
}
Also in onClick you could use view.getId() to get the resource ID and then use that in a switch/case block to identify each button and perform the relevant action.

servicestate of the android phone

In one of my app i wanted to check the service state of the android phone
before sending sms. I have used the following code to do that
//check service
ServiceState pstate = new ServiceState();
if(pstate.getState() != ServiceState.STATE_IN_SERVICE)
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
But the code always returns with OUT_OF_SERVICE ( value of 1 in +pstate.getState)
Please let me know what is the reliable way to check whether the phone is in STATE_IN_SERVICE or not?
This code was checked in FROYO version.
Not a satisfactory answer really, but I've had he same problem and kept wasting time, but it would just not work on my FROYO version aswell.
But using the TelephonyManager and PhoneStateListener this worked perfectly fine. For your case I'd suggest using a wrapper instead of instantiating the ServiceState directly, ie
//declare current state
ServiceState myServiceState = new ServiceState();
PhoneStateListener listener = null; // not sure if this is needed really..
// nifty getter
public ServiceState getServiceState(){ return myServiceState; }
//setup listener (eg. in onCreate)
TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
listener = new PhoneStateListener() {
#Override
public void onServiceStateChanged(ServiceState serviceState){
myServiceState = serviceState;
}
};
tm.listen(listener,PhoneStateListener.LISTEN_SERVICE_STATE);
// to be called when destroying your context
public void unregisterListener(){
// something like..
tm.listen(listener,PhoneStateListener.LISTEN_NONE);
}
//check service
ServiceState pstate = getServiceState();
if(pstate.getState() != ServiceState.STATE_IN_SERVICE)
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
A lazier solution would be moving the listener-setup into the getter and registering it only when actually called, if ever, and only saving if the service is available. ie
//declaration
boolean isAvailable = false;
PhoneStateListener listener = null;
// more nifty getter
public boolean isServiceAvailable(){
if (listener == null){
//setup listener if not yet done
TelephonyManager tm = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
listener = new PhoneStateListener() {
#Override
public void onServiceStateChanged(ServiceState serviceState){
isAvailable = serviceState.getState() == ServiceState.STATE_IN_SERVICE;
}
};
tm.listen(listener,PhoneStateListener.LISTEN_SERVICE_STATE);
}
return isAvailable;
}
// to be called when destroying your context
public void unregisterListener(){
// something like..
if (lister != null){
tm.listen(listener,PhoneStateListener.LISTEN_NONE);
}
}
//check service
if(! isServiceAvailable())
{
Log.v(TAG,"service state" +pstate.getState());
Toast.makeText(Myactivity.this, "error string", 2000).show();
return;
}
But be aware, that would require the listener to get called immediately upon registration, otherwise you'll end up with arbitrary results - so make sure to check that.

Categories

Resources