Start android app from sleeping device (not own activity)? - java

I'd like to start an app from a sleeping device.
First i do a wakelock to wakeup screen. But i cant get the device to unlock?
I know i can start my own activity with something like:
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
but as i'd like to start an 3rd party app app i cant use getWindow():
mContext.startActivity(mContext.getPackageManager().getLaunchIntentForPackage("com.sec.android.app.xy"));
Is there any way to set the flags before starting the activity?

If you know the third party's package and launcher activity names , this code should work (mPackage and mActivityName are those strings):
Intent LaunchIntent = new Intent();
LaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
LaunchIntent.setClassName(mPackage, mPackage + "." + mActivityName);
mContext.startActivity(LaunchIntent);
and mContext is the original application context (which you can instantiate as Context mContext = this.getApplicationContext();).

Related

Android: Uri Access Life Time from one activity to another

I have a helper method for choosing images and videos, let's call it Activity B.
So, this is how it works:
// were in Activity A
// user wants to choose a video
startActivityB(callbacks);
------------------------------------
// were in Activity B now
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
chooseVideoLauncher.launch(intent);
------------------------------------
// were in chooseVideoLauncher now
Uri videoURI = ...;
callbacks.passVideoURI(videoURI); // this way, Activity A gets the videoURI
// do some more things...
finish(); // so the helper activity B is finished now, as the video is chosen already
------------------------------------
// were in activity A again, but now we have the videoURI
// user clicked a button: "Upload video"
uploadVideo(videoURI);
This is the error I get:
java.lang.SecurityException: Permission Denial: opening provider com.miui.gallery.provider.GalleryOpenProvider from ProcessRecord{f5899ab 29899:com.xxx} (pid=xxx, uid=xxx) that is not exported from UID xxx
I have googled the error and found this SO thread: here
#CommonsWare explains the error in a comment and links his blog post: Uri Access Lifetime: Shorter Than You Might Think
So the error happens because the helper Activity B chose the file, so the access is tied to Activity B. No other activity has access, and as soon as Activity B is destroyed (what happens in my code), the access to videoURI is completely gone. So when I later try to upload the video, it throws this error.
I tried these solutions:
Create a local copy of the video and pass that copy to Activity A. This works, but is a bad solution. For longer videos the app crashes with a memory overflow. So it's not an option.
Setting the flags #CommonsWare mentioned. So the code looks like this:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
chooseVideoLauncher.launch(intent);
But this doesn't seem to change anything. The error message remains exactly the same. Am I setting them wrong?
#CommonsWare says using a service would also be a solution. I would prefer not to create a service purely for fixing this permission error. If there's no other solution, I will of course.
But is there no way to grant Activity A permission to that Uri as well?
The best solution, by far, is to combine Activity A and Activity B into a single activity. Use fragments or composables for separate screens.
Setting the flags #CommonsWare mentioned. So the code looks like this:
You would not set the flags on the ACTION_PICK Intent. Instead, Activity B needs to start Activity A (in addition to finish()). You would put the Uri into the "data" facet of the Intent (e.g., via setData()), and you would put the flags on that Intent. You would also need something like FLAG_ACTIVITY_REORDER_TO_FRONT or something to avoid having two copies of Activity A on the back stack.
For the second way Set the flags to get the long lifetime, you can try to add the following code, to get the permission, then start the activity
val contentResolver = applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)

Weird behaviour : Activity not getting started again when first started with FLAG_ACTIVITY_NEW_TASK

My scenario is,
When application starts then after user logs in I am starting an activity in the following manner,
Intent rangeFinderScreen = new Intent(YourLocationScreen.this, RangeFinderScreen.class);
rangeFinderScreen.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(rangeFinderScreen);
I am using Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK so that all previous activity stack gets cleared and it starts as a new task.
Then I have bottom bar to navigate between activities, so I have made a common listener (Activity) and implemented that in all the activities. It looks like the following,
public class CommonListenerForBottomButtons extends Activity implements View.OnClickListener{
Context context;
String buttonName;
public CommonListenerForBottomButtons(Context context, String buttonName){
this.context = context;
this.buttonName = buttonName;
}
#Override
public void onClick(View v) {
switch(buttonName){
case "play":
Intent rangefinder = new Intent(context, RangeFinderScreen.class);
rangefinder.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(rangefinder);
break;
// and so on more cases
}
}
}
Concern
If while starting the activity for first time I do the following,
Intent rangeFinderScreen = new Intent(YourLocationScreen.this, RangeFinderScreen.class);
startActivity(rangeFinderScreen);
Then all works.
But if I do it the following way (as I am doing now), i.e. by using rangeFinderScreen.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Then activity doesn't get started again.
However if I start activity from any other activity rather than the Common Listener Activity like,
Intent rangefinder = new Intent(MyGolflerScreen.this, RangeFinderScreen.class);
startActivity(rangefinder);
Then it starts.
EDIT
Below is how I am initializing Common Listener in all activities:
homeLinearLayout.setOnClickListener(new CommonListenerForBottomButtons(getApplicationContext(), "home"));
playLinearLayout.setOnClickListener(new CommonListenerForBottomButtons(getApplicationContext(), "play"));
weatherLinearLayout.setOnClickListener(new CommonListenerForBottomButtons(getApplicationContext(), "weather"));
messageLinearLayout.setOnClickListener(new CommonListenerForBottomButtons(getApplicationContext(), "message"));
myGolflerLinearLayout.setOnClickListener(new CommonListenerForBottomButtons(getApplicationContext(), "mygolfer"));
All other activities start except for the one which is initially started with the flag Intent.FLAG_ACTIVITY_NEW_TASK.
Manifest file entry
<activity
android:name=".RangeFinderScreen"
android:label="#string/title_activity_range_finder_screen"
android:screenOrientation="portrait" >
</activity>
If your concern is to manage all stacks i prefer to use all "singleTop" Activities and starting them with flag Intent.FLAG_ACTIVITY_CLEAR_TOP
It will manage all you want to do.
you can add launchMode in Manifest inside activity tag that is equal to "singleTop" .
Hope it works ...
Do not set the flag Intent.FLAG_ACTIVITY_NEW_TASK when you launch an Activity from another Activity within your application. This isn't necessary and is probably causing your problem.
Also, if you are starting a new Activity every time the user clicks on a button you will find that you are creating new instances of these activities every time, and will end up with a big stack of them after awhile. This probably isn't the desired behaviour either. To switch between activities that may already be in the task stack you can set the flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.

Initiliazing ParseLoginUI?

Where does one actually place the code to launch the ParseLoginUI activity?
ParseLoginBuilder builder = new ParseLoginBuilder(MainActivity.this);
startActivityForResult(builder.build(), 0);
Is it in the ParseLoginDispatchActivity? This was not made very clear at all within any of the official documentation:
https://github.com/ParsePlatform/ParseUI-Android
https://www.parse.com/docs/android/guide#user-interface
I'm importing ParseLoginUI into my existing app. What do I once I've installed everything, updated my manifests, my build.gradle and now want to actually launch the Login activity once my app launches?
Do I put something in my manifest to indicate that the ParseLoginActivity should launch first? That doesn't seem to work as an Activity from my main application is required to launch as the initial intent. I'm a little lost here... Any thoughts?
Well I did find one solution, albeit a trivial one:
Intent loginIntent = new Intent(MainActivity.this, ParseLoginActivity.class); startActivity(loginIntent);
I launched the above Intent with an options menu item, but you could do it with a button or whatever else suits your needs.
If you're importing ParseLoginUI into an existing app, it appears you can just launch ParseLoginActivity with a simple Intent. I wish they mentioned this on their integration tutorial. Seems like the most straightforward way to get it running.
This solution definitely launches the Activity you want, but it doesn't check for whether the user is logged in or not and hence doesn't redirect you to the appropriate pages in your log-in flow (which I believe has more to do with your Manifest). It does, however, allow you to successfully register a user and log in with Parse, which is a great start.
A better solution would be to add the following to the onCreate method in the Activity that launches when your app launches. So if when your app launches you land on FirstActivity, the following will check to see if you are logged in. If you are not, you will be sent the login screen, and if you are logged in you will be sent to the second Activity, which is presumably where your users will want to be when they open your app.
ParseUser currentUser = ParseUser.getCurrentUser();
if (currentUser != null) {
Intent launchMainActivity = new Intent(this, SecondActivity.class);
startActivity(launchMainActivity );
} else {
ParseLoginBuilder builder = new ParseLoginBuilder(FirstActivity.this);
startActivityForResult(builder.build(), 0);
}

Start two activities from Android application

I have an application A that wants to start an Activity in another application, B, which I don't own and cannot edit.
If B is already running and visible in recent apps, there's no problem in executing the wanted Activity of B using an Intent.
If B isn't running, I use the following code to execute its main Activity first, and then the one I want to execute:
String bPackage = "com.example.applicationb";
PackageManager pm = getPackageManager(this);
Intent main = pm.getLaunchIntentForPackage(bPackage);
Intent wanted = new Intent();
wanted.setPackage(bPackage);
wanted.setComponent(new ComponentName(bPackage,bPackage+".WantedActivity"));
main.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
wanted.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
wanted.setExtras(mPreviouslyCreatedBundle);
startActivity(main);
startActivity(wanted);
The wanted Activity executes, but after some seconds I get an error and it stops working. Am I setting the Intents in a wrong way?
Make sure u have setted exported="true" for activity you are trying to redirect to another package
Basically my idea is when your second paackage app leave u need :
android.os.process.killprocess(android.os.process.mypid())
and when you launch use flag as start new task :
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Closing an app from my app

I have developed an app which password protects another app ( say app A). So when I try to open app A, an activity pops on top of A prompting the user to enter password. Upon incorrect entry, it should close that activity and also close app A, which is directly under it.
Now I tried to do this using this code:
List<ActivityManager.RunningAppProcessInfo> pids = Unlock.am.getRunningAppProcesses();
for(int i = 0; i < pids.size(); i++)
{
ActivityManager.RunningAppProcessInfo info = pids.get(i);
if(info.processName.equalsIgnoreCase("com.A")){
pid = info.pid;
break;
}
}
android.os.Process.killProcess(pid);
But it does not work.
Later I realized that this is probably because the process of app A is not a direct child of my app's process ( that is, my app did not call app A). So is there anyway I can close but not necessarily kill app A from my app? What I mean to say is, killing app A is optional but closing it is mandatory.
I am not sure how to kill another app process. but you can take the user to home screen upon entering wrong password...
private void launchHomeScreen() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
finish(); // finish our Activity (based on your requirement)
}
Maybe this would work:
ActivityManager activityManager = (ActivityManager) context.getSystemService("activity");
activityManager.killBackgroundProcesses("com.A");
You'll need to add the following permission to your manifest.
<uses-permission> android:name="android.permission.KILL_BACKGROUND_PROCESSES" </uses-permission>

Categories