I am working on an app where I am drawing my custom lockscreen (An Activity) over the system's default lock.
Everything is working perfectly fine except one thing, I am using a reciever and whenever there is an incoming call, that reciever gets called and from inside that reciever I am closing the activity.
Note : This is happening only in case of OnePlus device, on any other device it's working perfectly.
private class CallStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
OverlayActivity overlayActivity = new OverlayActivity();
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// System.out.println("RINGING");
overlayActivity.finish();
// System.out.println("Activity has been closed!!");
break;
}
}
}
Both the lines before and after the code where I am closing the activity is working completely fine, but the activity is not getting closed.
And if you are creating Activity Object its not working at all you
needs and Actual Activity Object or Context of Activity to close it.
Related
I have a class in a service
MyClass m = new MyClass();
and inside my class I check if I have permission to overlay the view; if so, it's ok, otherwise I must start an activity
if (Settings.canDrawOverlays(mContext)) {
// draw over app
} else {
// start the activity
Intent i = new Intent(context,Calls.class);
context.startActivity(i);
}
When I start the activity I have a problem communicating between the class and the activity. I know how to use the interface but how can I register it in activity.
Some time I want to pass an object or data from the class to the activity or from the activity to the class... how can I do that?
I saw many examples in Stack Overflow about how to communicate between service and activity; they suggest to start the class from the activity but this does not work in my app because my class must be running all the time.
Perhaps you could use an event bus like mechanism where you can send or receive events through out your app, Though there are several libraries out there, I would recommend using Otto library for android.
Usage is pretty simple just register in your activity onCreate
Bus bus = new Bus();
bus.register(this);
For sending events
// example data to post
public class TestData {
public String message;
}
// post this data
bus.post(new TestData().message="Hello from the activity");
And subscribe to events like this
#Subscribe public void getMessage(TestData data) {
// TODO: React to the event somehow!
}
More info here
If you want to implement a communication pattern between a Service and an Activity, you should use a LocalBroadcastManager.
It will turn handy because, in case your Service is still on but your Activity
has been destroyed (very common situation), then the 'messagging' between the two will simply have no effect (no NPE or whatsoever will be thrown).
Step 1
Create a BroadcastReceiver in your Activity and define an ID / Filter
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service / Background Task
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Step 2
In your Activity register the broadcast in onResume() and unregister it in onPause().
#Override
protected void onResume() {
// Listen if a Service send me some data
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
#Override
protected void onPause() {
// I'm going to the background / or being destroyed: no need to listen to anything anymore...
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Your Activity is now ready to receive data from any other component in your Application.
If it's in the background, then there is no need to update the UI: in fact the Activity will not respond if in the background.
In the same way, if it's being garbage collected, the Receiver will be unregistered and the Activity will just not respond to anything.
If the Activity is resumed / restarted, onResume() will be triggered and the Receiver will be registered again.
Step 3
All you need to do right now, is send data from the Service.
Simply call
final Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER);
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
and your Activity will accordingly respond to the signal.
It's surprising how few people know about the LocalBroadcastManager and instead use some self-implemented callback / singleton pattern, which increases complexity and non-readability.
This pattern is built-in in Android, so you don't need external libraries. As for security, this ensures that your signals stay internal to your application: no data can therefore be read by other apps.
I similarly answered to another question here.
imagine this stack situation :
A - B- C - D - B , A, B and C are activities, but D is a service.
Basically, i have a service (D) and from that service i want to call an already existing activity (B).
I know that if I want to re-use an activity, all i got to do is to use the flags (or change the manifest) SingleTop (will re-use the activity if it is already on top) or SingleTask (will re-use the activity whether it is on top or not).
The problem is that since i am inside a Service, i will have to add the flag FLAG_ACTIVITY_NEW_TASK, so that i can call an activity. Also, i added SingleTask as a launch mode in my manifest so that that activity will be re-used.
This works fine since it re-uses the same activity and comes back to the method onNewIntent(Intent intent). The problem is that everything that i put as an extra on that intent comes as null. I try to send 2 strings and 2 booleans through that intent and all of them reach the onNewIntent(Intent intent) as null.
How can i solve this ? Do I have to do something inside the onNewIntent(Intent intent) method, before getting the extras ? Are there any better alternatives ?
PS:
I heard about the StartActivityForResult or something similar. That would only work 50% of the times, since this is for a " chat-like" application.
So I will be on the "chat", from where I go to another activity where i can select something to send. After that, i will go to the service, where the transfer is done, and then back to the "chat".
But when I receive something, I am already on the "chat", so the startActivityForResult wouldn't work in this case (the service to receive would be running on the background + I don't wan't to finish the receiving part, because i want to be always listening for something).
Here is the code from the service where i try to re-launch the single activity :
Intent transfRec=new Intent(ServerComm.this ,TransferRecordActivity.class);
transfRec.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
transfRec.putExtra("receivedFilePath",appName+".apk");
transfRec.putExtra("joinMode","appselection");
transfRec.putExtra("nameOfTheApp",appName);
transfRec.putExtra("received",false);
transfRec.putExtra("isHotspot",isHotspot);
startActivity(transfRec);
Here is the code of my onNewIntent(Intent intent) :
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
System.out.println("I am here in the new intent");
if(intent==null){
System.out.println("Intent is null inside the new intent method !!!");
}
tmpFilePath=getIntent().getStringExtra("receivedFilePath");
System.out.println("The tmpFilePath is : "+tmpFilePath);
received=getIntent().getBooleanExtra("received",true);
nameOfTheApp=getIntent().getStringExtra("nameOfTheApp");
isHotspot=getIntent().getStringExtra("isHotspot");
System.out.println("O received boolean esta a : : : "+received);
textView.setVisibility(View.GONE);
receivedFilePath= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+tmpFilePath;
System.out.println("transfer REcord Activity _: the received file path is :::: " +receivedFilePath);
getReceivedApps();
adapter= new HighwayTransferRecordCustomAdapter(this,listOfItems);
receivedAppListView.setAdapter(adapter);
EDIT: As you guys can see i check if the intent is null, and it is not, since it doesn't do the system.out.println that there is on that condition !
The issue is that you are calling getIntent() within your onNewIntent(). From the docs for getIntent():
Return the intent that started this activity.
Therefore, you are getting the intent provided to onCreate(). To get the intent supplied to onNewIntent(), you simply use intent which is provided in the method signature:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
tmpFilePath=intent.getStringExtra("receivedFilePath");
...
}
After I receive a response with Volley, I have to get back to the main fragment.
I have two different volley requests , depending on some condition, I'll call it 'a' in this example.
The weird thing is the when a==1, popBackStack gets me successfully to the main fragment .
When a==0 it crashes and I receive java.lang.IllegalStateException Fragment not attached to Activity
I tried creating a new main fragment (transaction.commit....) but it didn't help.
if( a == 0 )
{
VolleyManager.add(jsnObj,
new RequestListener() {
#Override
public <T> void onSuccess(T object) {
mFragmentManager.popBackStack(DataManager.BACK_STACK_KEY_MAIN_FRAGMENT, 0);
}
});
}
else if( a==1 )
{
VolleyManager.update(jsnObj,
new RequestListener() {
#Override
public <T> void onSuccess(T object) {
mFragmentManager.popBackStack(DataManager.BACK_STACK_KEY_MAIN_FRAGMENT, 0);
}
});
}
Error -
java.lang.IllegalStateException: Fragment MainFragment{6aaaf7f} not attached to Activity
at android.app.Fragment.getResources(Fragment.java
The problem seems to be with the getResources(), but I do the same thing when a==1 and I've got no problems at all.
It seems like that by the time AsyncTask finishes and calls onPostExecute, the MainFragment has been detached from its activity. So either the activity has already been destroyed or fragment was never attached.
So if fragment is not attached to the activity, it can't access resources because that requires context and fragment doesn't have but activity does.
So you should check if activity is null or not before calling getResources.
Update the code like this:
if(getActivity()!=null){
String streetFormat = getActivity().getResources().getString( R.string.address_name_string );
....
}
You have to cancel your requests on
onDestroyView()
method of the fragment or check if the fragment is already alive and added to host activity or not
I'd go with something like this:
onDestroyView(){ Volley.cancelAllRequests() }
or
onResponse(){ if(getActivity() != null && isAdded(){ // here handle the response and update views, otherwise just cache the response!}}
getResources() must be called from something that has Context, like the activity. The fragment itself does not have the Context since it does not implement it. If you're using getResources() in a fragment, you can try this:
String streetFormat = getActivity().getResources().getString( R.string.address_name_string );
I have three java files in my Android project. Two are activities (MainActivity and GeoActivity) and one is a plain java file (PostHttp -> sends data to server via the HTTP POST)
I switch over to GeoActivity via a simple button on-click method. GeoActivity returns the co-ordinates of the current location in a TextView AND sends them to a remote server via the HTTP POST.
I have a Handler.class which executes sends the Post Message after a delay of 50s. Something like this below. The problem i have is that when i click the back button and switch over to MainActivity i can still see in LogCat the echoes receiving from the server that the data is still being sent. How can i stop that?
GeoActivity.class
public class GeoActivity extends Activity {
Location location;
private Handler mHandler = new Handler();
protected void onCreate(Bundle savedInstanceState) {
....
if(location != null){
mHandler.postDelayed(updateTask,0);
}
...
}
...
public Runnable updateTask = new Runnable(){
public void run(){
mlocListener.onLocationChanged(location);
//send coordinates with a delay of 50s
new PostHttp(getUDID(),latitude,longitude).execute();
mHandler.postDelayed(updateTask, 50000);
}
Try acting on the activity's life cycle.
For example:
#Override
protected void onStop() {
super.onStop(); // Always call the superclass method first
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
ContentValues values = new ContentValues();
values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());
getContentResolver().update(
mUri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
);
}
This doesn't destroy the activity, it will reside in memory. However, you can always resume when needed.
Source:
Stopping and Restarting Android Activities
I just started to look into Android instrumentation tests but have some problems with getting my tests executed. Here is what I tried:
Using Android Studio and gradle, I created a simple test class within src/instrumentTest/java/. Here it is:
package at.example.test;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import at.example.activity.MainActivity;
public class BasicAppTestCase extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity activity;
public BasicAppTestCase() {
super(MainActivity.class);
}
#Override protected void setUp() throws Exception {
super.setUp();
activity = getActivity();
}
public void testAppHomeButtonExists() {
View homeButton = activity.findViewById(android.R.id.home);
assertNotNull("Home button does not exist", homeButton);
}
}
Next, I start the test using by right clicking on my project and selecting Run 'All Tests'. Android Studio executes assembleDebug and assembleTest tasks for my project, and installs both apk files onto my test device.
Afterwards, the app is successfully started on my test device. The setUp() method is getting executed (I checked this by putting a failing assert into the method as well as using logcat) and then the test execution hangs, showing Running tests... and testAppHomeButtonExists as being currently executed.
The test execution won't proceed until I change the activity state by minimizing the app pressing the home button or opening the app switcher. Then the test method testAppHomeButtonExists gets executed and (depending on the methods body) succeeds or fails. Again, I tested this behavior using assert calls and the logcat output.
UPDATE:
This is what the TestRunner is logging to my device's logcat stream:
11-11 15:34:59.750 24730-24748/at.example.activity I/TestRunner﹕ started: testAppHomeButtonExists(BasicAppTestCase)
Up until I stop the app nothing more is logged. After stopping the activity following is logged:
11-11 15:35:05.205 24730-24748/at.example.activity I/TestRunner﹕ finished: testAppHomeButtonExists(BasicAppTestCase)
11-11 15:35:05.205 24730-24748/at.example.activity I/TestRunner﹕ passed: testAppHomeButtonExists(BasicAppTestCase)
Am I doing something wrong? Am I missing something? What could cause this behavior?
Thanks in advance!
Instead of checking view like that u can try something like this :
public class BasicAppTestCase extends ActivityInstrumentationTestCase2<MainActivity> {
private MainActivity activity;
private Button;
public BasicAppTestCase() {
super(MainActivity.class);
}
#Override protected void setUp() throws Exception {
super.setUp();
activity = getActivity();
button = (Button) activity
.findViewById(android.R.id.home);
}
public final void testPreconditions() {
assertNotNull(activity);
}
public final void testFieldsOnScreen() {
final Window window = tAes_Activity.getWindow();
final View origin = window.getDecorView();
assertOnScreen(origin, button);
}
}
I have found the problem: I created an infinite invalidation loop inside one of my views onDraw() method. A velociraptor should eat me for using old code without checking it first. This is what the view's drawing method looked like:
#Override protected void onDraw(Canvas canvas) {
// Get the current location on screen in pixels (left = 0)
int[] location = new int[2];
this.getLocationOnScreen(location);
// Translate the canvas for the same location as its current offset (resulting in a doubled shift).
canvas.translate(location[0], 0);
// Now draw the translated content.
super.onDraw(canvas);
this.invalidate();
}
The above drawing method created a "faked parallax effect" of the view's content. The problem was, that although this did not result in a ANR it caused the hosting Activity to never go idle causing my test's getActivity() method not to return as it's implementation waits for an idle activity (meaning the setup completed). The question Android animation causing "Activity idle timeout for History Record" on start up is a similar problem. My quick solution was to defer the invalidate() call to the parent ViewPager. Since my parallax effect needed only to be updated when the position of my page changed I am now using a ViewPager.OnPageChangeListener() that updates child views as soon as they move.
This fixes the problem for me! My tests are running now and are fully functional!