How to close/exit outside settings intent created by the application - java

I'm currently working on a simple application that is used to force stop some applications with the help of Accessibility permission. It automatically opens the Application Info Settings page and presses the Force Stop button (The main part is working fine).
But After the process, I can't minimize or close the settings page. I used onAppStopped() method (starts the MainActivity intent), but it repeats the process recursively. I think it is because the settings page is not a part of the main application.
Is there any way to override this issue?
MainActivity
protected void onCreate(Bundle savedInstanceState) {
FSAccessibilityService.setClient(this);
forceStopApp("package name");
}
public void forceStopApp(String packageName) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.parse("package:" + packageName);
intent.setData(uri);
startActivity(intent);
}
#Override
public void onAppStopped() {
startActivity(new Intent(this, MainActivity.class);
}
FSAccessibilityService extends AccessibilityService
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
performForceStop(event);
}
private void performForceStop(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
performClickButtonByText(source, "FORCE STOP");
performClickButtonByText(source, "OK");
getClient().onAppStopped();
}
public interface FSClient {
void onAppStopped();
}

Related

Disable button after returning from an intent

Afternoon all I need to call an intent and upon returning disable the button for X seconds.
I have tried variations of the following, which either disable the button immediately and then enable or do not do what I need full stop.
Guarding.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Guarding.setEnabled(false);
SharedPref.write(SharedPref.SCANTYPE,"GUARDING");
Intent intent = new Intent(Menu.this, CmxScanner.class);
startActivity(intent);
Guarding.postDelayed(new Runnable() {
public void run() {
Guarding.setEnabled(true);
//Log.d(TAG,"resend1");
}
},10000);
}
});
So on first entry to the menu i have a button that is enabled, after clicking it must call the intent and upon returning disable the button again for X seconds. Before it will enable and allow a second request to the Intent
You can register your calling activity for a result as explained in the Android docs here. Then in the result callback you simply enable the button after 10 seconds:
ActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(),
new ActivityResultCallback<Uri>() {
#Override
public void onActivityResult(Uri uri) {
Guarding.postDelayed(new Runnable() {
public void run() {
Guarding.setEnabled(true);
}
}, 10000);
}
}
});

show app lock pattern dialog when unlocking the phone

I have MainActivity and on its onResume method I call pattern lock to create and confirm user identity. User visits and leave this MainActivity back and forth while active on the app as well as when phone is in sleep mode and user unlocks it. These both scenarios will call onRestart, onStart and onResume methods, but I only want to revoke the pattern in unlock scenario.
handlePattern() method needs a proper distinguishing to be called.
How to distinguish this when I call the handlePattern method ?
MainActivity.class
onCreate(){}
onResume(){
//help needed to know that user is just visiting activity in app back and forth
or came back after unlocking the screen.
if(isPatternCallRequired){
handlePattern()
}
}
In your onStop() method call you can check if the player is in sleep mode and cache the boolean.
PowerManager pm = (PowerManager)
_context.getSystemService(Context.POWER_SERVICE);
boolean isInSleepMode = !pm.isScreenOn();
Check for the build version
if( Build.VERSION.SDK_INT >= 20)
// use isInteractive()
else
// use isScreenOn()
in onRestart which will get called when you resume from sleep - based on the cached value you can show the pattern to unlock.
You may need to reset the cached value once you are done using it.
onResume may not be a right API for the call as it will be called even when your activity loads.
Edited answer based on your comment
You can try ActivityLifecycleCallbacks too like this,
First, Register your Application in your Application class.
public class StackApp extends Application {
private static final String TAG = StackApp.class.getSimpleName();
public static final String INTENT_ACTION_APP_STATE_CHANGE = "intent_action_app_state_change";
public static final String INTENT_DATA_IS_IN_BACKGROUND = "intent_data_is_in_background";
private static int mNumRunningActivities = 0;
private static AtomicBoolean mIsAppInForeground = new AtomicBoolean();
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= 14) {
// registerActivityLifecycleCallbacks is supported only from the SDK version 14.
registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
mNumRunningActivities++;
if (mNumRunningActivities == 1) {
notifyAppState(false);
Log.i(TAG, "APP IN FOREGROUND");
}
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
mNumRunningActivities--;
if (mNumRunningActivities == 0) {
notifyAppState(true);
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
/**
* To notify App state whether its in ForeGround or in Background
*
* #param isInBackground
*/
private void notifyAppState(boolean isInBackground) {
if (isInBackground) {
mIsAppInForeground.set(false);
} else {
mIsAppInForeground.set(true);
}
sendAppStateChangeBroadcast(isInBackground);
}
public static boolean isInForeground() {
return mIsAppInForeground.get();
}
private void sendAppStateChangeBroadcast(boolean isInBackground) {
Log.i(TAG, "sendAppStateChangeBroadcast - isInBackground : " + isInBackground);
Intent intent = new Intent();
intent.setAction(INTENT_ACTION_APP_STATE_CHANGE);
intent.putExtra(INTENT_DATA_IS_IN_BACKGROUND, isInBackground);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And register the broadcast and listen whether the App is going background or foreground like this Sample Activity example
public class SampleMyActivity extends AppCompatActivity {
private OnAppStateReceiver mAppStateReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_my);
mAppStateReceiver = new OnAppStateReceiver();
IntentFilter filter = new IntentFilter(StackApp.INTENT_ACTION_APP_STATE_CHANGE);
LocalBroadcastManager.getInstance(this).registerReceiver(mAppStateReceiver, filter);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mAppStateReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mAppStateReceiver);
}
}
private class OnAppStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TextUtils.isEmpty(action) && StackApp.INTENT_ACTION_APP_STATE_CHANGE.equalsIgnoreCase(action)) {
boolean isGoingBackground = intent.getBooleanExtra(StackApp.INTENT_DATA_IS_IN_BACKGROUND, false);
if (isGoingBackground) {
//Your app is not vissible to the use
} else {
// App is visible to the user.
}
}
}
}
}
Note: If you want to listen in Multiple Activity you can create a base
class and add the listener there and you can do the operation, In that
case you can reduce a lot of code.

Go to an activity from anywhere

I am implementing a login system. The user needs to be redirected to the login activity from any previous activity if the token is no longer valid. I can go to the login activity with this
new Intent(CurrentActivity.this, NextActivity.class);
But this needs the current activity. I just want to go to the login activity no matter where I am. I cannot know where I am because this is inside an entirely different package.
you should probably register in the Application class to ActivityLifecycleCallbacks and if the user is not registered send them to the correct Activity.
just be sure to not endlessly send them from the login page to itself
EDIT:
adding some code and explanation.
In order to figure out if an Activity that shouldn't be alive is going through lifecycle events you'll need to implement some sort of a gate keeper. Previously it used to be some sort of static state that is kept in the Application class and holds the current activity and sometime even the stack of current activities.
This was far from a complete solution and had issues due to different tasks and even isolated procesies.
In API 14 Android introduced the Activity lifecycle callbacks which can be passed into the method registerActivityLifecycleCallbacks int the Application class.
What you want to do basically is the following:
class ThepooshApplication extends Application {
private static sIsRegistered = false;
public static setIsRegistered(boolean isRegistered) { sIsRegistered = isRegistered; }
public void onCreate() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(){
#Override
void onActivityCreated(Activity activity, Bundle savedInstanceState){
if (!sIsRegistered && !(activity instanceof LoginActivity)) {
Intent loginIntent = new Intent(this, LoginActivity.class);
loginIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(loginIntent);
}
}
#Override
void onActivityStarted(Activity activity) { /*empty method*/ }
#Override
void onActivityResumed(Activity activity) { /*empty method*/ }
#Override
void onActivityPaused(Activity activity) { /*empty method*/ }
#Override
void onActivityStopped(Activity activity) { /*empty method*/ }
#Override
void onActivitySaveInstanceState(Activity activity, Bundle outState) { /*empty method*/ }
#Override
void onActivityDestroyed(Activity activity) { /*empty method*/ }
});
}
}
You must add FLAG_ACTIVITY_NEW_TASK flag to your intent
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Try some like this
Intent i = new Intent();
i.setClass(this,TestActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Replace TestActivity.class for your target activity

How to update Activity from thread started in another activity?

I have a Main activity and after click on button I start thread (but the thread is hidden in library and I have only callback in Main activity.
Now I want to start another activity (call A) where I want to put results from the thread.
Below is simplified code:
public class Main extends Activity {
XManager.ResultsCallback xResultsCallback = new XManager.ResultsCallback() {
// the method is called every 10 sec.
#Override
public void onResult(ArrayList<String> texts) {
}
};
XManager xManager = new xManager(xResultsCallback);
View.OnClickListener onClick = new View.OnClickListener() {
#Override
public void onClick(View arg0) {
XManager.start();
Intent i = new Intent(Main.this, A.class);
startActivity(i);
}
};
}
I want to update the content of A activity each time when onResult() method is called. How to do that?
Use LocalBroadcastManager,
In your Main Activity create function :
private void sendResult() {
Log.d("sender", "Broadcasting message");
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my result!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
and add BroadcastReceiver in your A Activity
private BroadcastReceiver onResult= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("jazzy","onReceive called");
}
};
add on OnCreate
#Override
public void onCreate(Bundle savedInstanceState) {
// Register to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
add onDestroy
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
I have a suggestion that you should do as follows:
Start Your Activity A on button click
Inside Activity A declare your XManager instance with a callback present in A itself
Then start your XManager as XManager.start(); that way you would be getting all the callbacks in your desired activity.
Have a great day!
I think if you want to decouple the logic, beside you can use the Android BroadcastReceiver, the another flexible choice is to use the Bus
And you can integrate it with gradle easily
dependencies {
compile 'com.squareup:otto:+'
}

How to restore to exact activity after coming from Paused or Resumed state in android

I have two simple activities MainActivity and ThreadActivity. I call ThreadActivity from MainActivity.
The code ofMainActivity:
public class MainActivity extends Activity {
private Button btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.btn2);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ThreadActivity.class);
startActivity(intent);
}
});
}
}
And the code of ThreadActivity:
public class ThreadActivity extends Activity{
private Thread myThread=null;
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
void runThread(){
myThread = new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
Log.d("Thread", "I am running " + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}
}
};
myThread.start();
}
}
When I start ThreadActivity I run a simple thread and change button text.
My Problem
When I loose focus from application, i.e when application becomes partially visible, and I come back I am redirected to ThreadActivity and the thread is still running.
When I leave application running and open a new application, and then come back, I am again redirected to ThreadActivity.
The problem is when I press back button, I am being redirected to first activity MainActivity. But instead when back button is being pressed I want my application to exit. In a few words MainActivity should not exist in the stack.
I tried setting android:noHistory="true" for MainActivity but I could not keep the behavior explained in bullet points working. I mean when I pause the application and restore it back, it redirected me to MainActivity instead of ThreadActivity.
Just call finish() when starting the ThreadActivity:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ThreadActivity.class);
startActivity(intent);
finish();
}
});
BUT there is a problem with your app. Use a Timer to set the text of the Button! By using a Thread like you do you are creating a memory leak and that is very bad. Try this:
private int i = 0;
private Timer timer;
private final TimerTask timerTask = new TimerTask() {
#Override
public void run() {
btn.post(new Runnable() {
#Override
public void run() {
btn.setText("#" + i++);
}
});
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
timer = new Timer();
timer.schedule(timerTask, 300, 300);
}
});
}
#Override
public void onPause() {
super.onPause();
if(timer != null) {
timer.cancel();
}
}
From your comments to other peoples' answers, it seems like you want the ThreadActivity to always be resumed instead of the MainActivity when your thread is running.
Do the thread in a Service - the service will mean your application's VM is likely to be kept alive longer. An app with no foreground activities can be killed off quite quickly (even if it has background threads running).
You need to persist that the thread is running, and the progress (if, in the real code that is applicable). Currently you could persist the value of i in your while loop.
Your application's default launcher activity (MainActivity) will launch when you click on it from your launcher. Check if the persisted value has been set, and act as though the user started the ThreadActivity in onCreate, if you finish() in onCreate, the user won't see any UI from the MainActivity
Depending on what you're actually trying to do, you might be able to resume the thread depending on the progress persisted - in this example, you could start from the persisted value of i (instead of 0).
What I had to is set android:noHistory="true" for MainActivity and in the ThreadActivity I had to add the solution mention by #NeTeInStEiN in this quesiotn
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyDown(keyCode, event);
}

Categories

Resources