http://florent-dupont.blogspot.ro/2015/02/android-5-screen-pinning.html
From a pinned app, you cannot start a secondary app, unless this one
has the same shared user ID (which means that the sharedUserIdis set
in the AndroidManifest.xml and that second application is packaged
with the same certificate). Other apps’ Activities won’t be allowed to
be started and doing so (by using Context.startActivity()) will simply
be ignored.
I have done just those two things above but startActivity() is still getting ignored.
From https://developer.android.com/reference/android/R.attr.html#lockTaskMode:
If the system is already in lockTask mode when a new task rooted at
this activity is launched that task will or will not start depending
on whether the package of this activity has been whitelisted.
It looks tome like I have taken the necessary steps for this to work.
Anybody out there who got this working ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
ComponentName deviceAdmin = new ComponentName(this, AdminReceiver.class);
mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
if (!mDpm.isAdminActive(deviceAdmin)) {
Toast.makeText(this, getString(R.string.not_device_admin), Toast.LENGTH_SHORT).show();
}
if (mDpm.isDeviceOwnerApp(getPackageName()))
{
mDpm.setLockTaskPackages(deviceAdmin, new String[]{getPackageName(), "com.that.other.package"});
try
{
enableKioskMode(true);
PackageManager pm = this.getPackageManager();
Intent it = pm.getLaunchIntentForPackage("com.that.other.package");
if (null != it) {
this.startActivity(it);
Log.d(_TAG, "Started activity for com.that.other.package");
}
}
catch (Exception e)
{
Log.e(_TAG, e.getMessage());
finish();
}
} else {
Toast.makeText(this, getString(R.string.not_device_owner), Toast.LENGTH_SHORT).show();
}
}
private void enableKioskMode(boolean enabled) throws Exception
{
if (enabled)
{
if (mDpm.isLockTaskPermitted(this.getPackageName()))
{
startLockTask();
mIsKioskEnabled = true;
mButton.setText(getString(R.string.exit_kiosk_mode));
} else {
Toast.makeText(this, getString(R.string.kiosk_not_permitted), Toast.LENGTH_SHORT).show();
}
} else {
stopLockTask();
mIsKioskEnabled = false;
mButton.setText(getString(R.string.enter_kiosk_mode));
}
}
Turned out I was missing the android:taskAffinity tag. Point it to the same strings in both packages and startActivity() should start behaving.
Related
I'm stuck on figuring out how to ask for permission to access a USB com device, wait for the user input, then proceed accordingly if permission granted. I can't figure out what the "onRequestPermissionsResult" is for when UsbManager asks for permissions. I noticed that listener never gets called when UsbManager requests permission, so its not used in the way I originally thought.
This code is all in the MainActivity.
Here I'm setting my Intent for when my USB device is connected or disconnected, and initializing UsbManager.
Note I'm not using LOGCAT to log debug messages because my Android device has to be disconnected from Android Studio to plug in the USB com device I'm developing the app for. Instead I'm logging to the app UI.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DoIntent();
m_manager = (UsbManager) getSystemService(Context.USB_SERVICE);
}
private void DoIntent () {
m_usbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
try {
OnDeviceConnected();
// m_textViewDebug.setText("USB Connected");
} catch (Exception e) {
m_textViewDebug.setText(e.getMessage());
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
m_port = null;
m_serialIoManager = null;
m_isInitialized = false;
m_textViewDebug.setText("USB Disconnected");
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(m_usbReceiver , filter);
Then here is what happens when a device is connected. I want to establish permission as soon as its connected.
private void OnDeviceConnected () throws Exception {
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x239a, 0x800c, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(m_manager);
UsbDeviceConnection connection = null;
UsbSerialDriver driver = drivers.get(0);
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
m_manager.requestPermission(driver.getDevice(), usbPermissionIntent);
/// Need some kind of pause or check for permissions here before executing forward.or
/// handle everything after on a different routine called after permission has been selected.
/// Continues to execute before user has time to respond to permissions.
try {
connection = m_manager.openDevice(driver.getDevice());
} catch (Exception e) {
throw new Exception(e.getMessage());
}
if (connection == null) {
throw new Exception ("Could not open device.");
}
m_port = driver.getPorts().get(0);
try {
m_port.open(connection);
m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
m_port.setDTR(true);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
m_executor.submit(m_serialIoManager);
m_isInitialized = true;
}
Then here is what I'm originally trying to do once permission has been granted.
I can't get any logging message to appear from this scope, so I believe it's never being called and I'm using it incorrectly.
#Override
public void onRequestPermissionsResult(final int requestCode, String[] permissions, int[] grantResults) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
/// Never gets called :/
m_textViewDebug.setText(Integer.toString(requestCode));
}
});
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
/// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
/// permission was granted, yay! Do the
/// contacts-related task you need to do.
} else {
/// permission denied, boo! Disable the
/// functionality that depends on this permission.
}
return;
case USB_PERMISSION_GRANTED: { /// Not the real enum because I'm not sure where to find what it is.
try {
/// Need to somehow pass driver from OnDeviceConnected to this scope, or make it class property.
connection = m_manager.openDevice(driver.getDevice());
} catch (Exception e) {
throw new Exception(e.getMessage());
}
if (connection == null) {
throw new Exception ("Could not open device.");
}
m_port = driver.getPorts().get(0);
try {
m_port.open(connection);
m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
m_port.setDTR(true);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
m_executor.submit(m_serialIoManager);
m_isInitialized = true
}
/// other 'case' lines to check for other
/// permissions this app might request.
}
}
I'm trying to log what requestCode is so I can write a case for whatever the USB permission code is. I can't find a compiled list anywhere in the docs of what all the options are that requestCode could be.
MY_PERMISSIONS_REQUEST_READ_CONTACTS actually throws a compile error because I have no idea where it comes from. This guide isn't very detail with USB specifically. That guide is also where I got the switch statement in my above routine.
EDIT:
I tried messing around with UsbManager.EXTRA_PERMISSION_GRANTED to see if that could work. I added it as an action to my intent filter.
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.EXTRA_PERMISSION_GRANTED);
registerReceiver(m_usbReceiver, filter);
Then I'm logging what the action of the intent is coming into my Broadcast Receiver, but nothing happens when a USB permission is granted or denied.
What kind of action or event is triggered when "OK" is tapped in this above image? Been scratching my head at this for a few days poking at the API.
I finally figured it out taking a closer look at this.
I have this before trying to establish an intent filter.
public static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
IntentFilter filter = new IntentFilter();
And I changed it to this.
private static final String ACTION_USB_PERMISSION = BuildConfig.APPLICATION_ID + ".USB_PERMISSION";
m_permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
The key difference was that new IntentFilter needed that ACTION_USB_PERMISSION string.
Now in my Broadcast Receiver, I have this condition that is being called as expected.
else if (ACTION_USB_PERMISSION.equals(action)) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
m_textViewDebug.setText("USB Permission Granted");
try {
OnDevicePermissionGranted();
} catch (Exception e) {
m_textViewDebug.setText(e.getMessage());
}
}
else {
m_textViewDebug.setText("USB Permission Denied");
}
}
Took me a while to figure out how to use EXTRA_PERMISSION_GRANTED.
When this here says "EXTRA_PERMISSION_GRANTED containing boolean indicating whether permission was granted by the user" I'm thinking this whole time I'm trying to find a boolean flag on some object to verify permission. I didn't realize I had to call a special method on the intent and supply that string to get my true or false. Seems very counter intuitive to me.
I realize the biggest mistake was not supplying the correct string when making the new intent filter. I found a bunch of other examples that had it without any arguments.
In my application I want to change the password of the lock screen programmatically. So I wrote this method to reset the password:
#TargetApi(26)
private void changePasswordWithToken() {
SecureRandom secureRandom = new SecureRandom();
byte[] token = secureRandom.generateSeed(32);
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getApplicationContext().getSystemService(
DEVICE_POLICY_SERVICE);
if (devicePolicyManager != null) {
devicePolicyManager.setResetPasswordToken(compName, token);
devicePolicyManager.resetPasswordWithToken(compName, "1234", token, 0);
}
}
When I call the method I get this error on my device running Android 9 SDK 27
va.lang.SecurityException: Admin ComponentInfo{com.xxx.xxx/com.xxx.xxxx.MyAdmin} does not own the profile
at android.os.Parcel.createException(Parcel.java:1942)
at android.os.Parcel.readException(Parcel.java:1910)
at android.os.Parcel.readException(Parcel.java:1860)
at android.app.admin.IDevicePolicyManager$Stub$Proxy.setResetPasswordToken(IDevicePolicyManager.java:9995)
at android.app.admin.DevicePolicyManager.setResetPasswordToken(DevicePolicyManager.java:3091)
at com.ssaurel.lockdevice.MainActivity.changePasswordWithToken(MainActivity.java:136)
at com.xx.xx.MainActivity.onClick(MainActivity.java:93)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
...
Before I call this method, I' getting the device admin permissions with this method
private void provisionDeviceAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(EXTRA_DEVICE_ADMIN, compName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"Additional text explaining why we need this permission");
startActivityForResult(intent, RESULT_ENABLE);
}
My policies looks like this
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
<reset-password />
</uses-policies>
</device-admin>
Please have a look at the documentation, it clearly states there that:
Called by device or profile owner to force set a new device unlock
password or a managed profile challenge on current user. This takes
effect immediately.
From your code it does not look as if you are a "device or profile owner"; please don't mix that up with "device admin" which your apps seems to be (or is trying to get not sure if it is really successful from your code).
For me this solution worked out:
At first, define admin device permissions
policies.xml
<?xml version="1.0" encoding="utf-8"?>
<device-admin>
<uses-policies>
<reset-password/>
</uses-policies>
</device-admin>
Then create a class that extend DeviceAdminReceiver
public class MyAdmin extends DeviceAdminReceiver {
#Override
public void onEnabled(Context context, Intent intent) {
Toast.makeText(context, "Device Admin : enabled", Toast.LENGTH_SHORT).show();
}
#Override
public void onDisabled(Context context, Intent intent) {
Toast.makeText(context, "Device Admin : disabled", Toast.LENGTH_SHORT).show();
}
/**
* Generates a {#link ComponentName} that is used throughout the app.
* #return a {#link ComponentName}
*/
public static ComponentName getComponentName(Context context) {
return new ComponentName(context.getApplicationContext(), MyAdmin.class);
}
}
Get admin device permission with this function in your MainActivity
private void provisionDeviceAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(EXTRA_DEVICE_ADMIN, MyAdmin.getComponentName(this));
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"Additional text explaining why we need this permission");
startActivityForResult(intent, RESULT_ENABLE);
}
Then provision a working profile for your app in the MainActivity
private void provisionManagedProfile() {
Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
// Use a different intent extra below M to configure the admin component.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//noinspection deprecation
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
MyAdmin.getComponentName(this));
} else {
final ComponentName component = new ComponentName(this,
MyAdmin.class.getName());
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
component);
}
if (intent.resolveActivity(this.getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
this.finish();
} else {
Toast.makeText(this, "Device provisioning is not enabled. Stopping.",
Toast.LENGTH_SHORT).show();
}
}
After that set the application package to the working profile
private void setAppEnabled(String packageName, boolean enabled) {
PackageManager packageManager = getPackageManager();
DevicePolicyManager devicePolicyManager =
(DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
try {
int packageFlags;
if(Build.VERSION.SDK_INT < 24){
//noinspection deprecation
packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES;
}else{
packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES;
}
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
packageFlags);
// Here, we check the ApplicationInfo of the target app, and see if the flags have
// ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation.
if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
// If the app is not installed in this profile, we can enable it by
// DPM.enableSystemApp
if (enabled) {
devicePolicyManager.enableSystemApp(MyAdmin.getComponentName(this), packageName);
} else {
// But we cannot disable the app since it is already disabled
Log.e("TAG", "Cannot disable this app: " + packageName);
return;
}
} else {
// If the app is already installed, we can enable or disable it by
// DPM.setApplicationHidden
devicePolicyManager.setApplicationHidden(
MyAdmin.getComponentName(this), packageName, !enabled);
}
Toast.makeText(this, enabled ? "Enabled" : "Disabled",
Toast.LENGTH_SHORT).show();
} catch (PackageManager.NameNotFoundException e) {
Log.e("TAG", "The app cannot be found: " + packageName, e);
}
}
Create a method to generate random password tokens
private byte[] generateRandomPasswordToken() {
try {
return SecureRandom.getInstance("SHA1PRNG").generateSeed(32);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
Finally implement this method to reset the lock screen password with token
#TargetApi(26)
private void changePasswordWithToken() {
byte[] token = generateRandomPasswordToken();
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getApplicationContext().getSystemService(
DEVICE_POLICY_SERVICE);
KeyguardManager keyguardManager = (KeyguardManager) this.getSystemService(KEYGUARD_SERVICE);
keyguardManager.createConfirmDeviceCredentialIntent(null, null);
if (devicePolicyManager != null) {
devicePolicyManager.setResetPasswordToken(MyAdmin.getComponentName(this), token);
devicePolicyManager.resetPasswordWithToken(MyAdmin.getComponentName(this), "1234", token, 0);
}
}
In my application, i start another application (not activity) with this code :
protected void launchApp(String packageName) {
Intent mIntent = getPackageManager().getLaunchIntentForPackage(
packageName);
if (mIntent != null) {
try {
startActivity(mIntent);
} catch (ActivityNotFoundException err) {
Toast t = Toast.makeText(getApplicationContext(),
"App not found", Toast.LENGTH_SHORT);
t.show();
}
}
}
but i would like this application (launched by packageName) run in background and not disturb the UI.
Is it possible ?
Thanks!
you can use broadcast receiver in target app and start it with broadcast
Hope it will help
you can use this
startActivity(getPackageManager().getLaunchIntentForPackage("com.example.appName"));
further information please see this link
Android - How to start third party app with package name?
I make a phone call from an Activity and when call ends I want to come back to application. I tried all the solutions available on stackoverflow. One of them used to work for few minutes but not working now.
I tried using recreate() method which successfully calls onCreate method of an Activity but app is not in foreground. I tried using various flags such as FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_CLEAR_TASK, FLAG_ACTIVITY_NO_HISTORY. But does not work.
Code to go back to application from call app :
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
// If call ringing
if (state == TelephonyManager.CALL_STATE_RINGING) {
}
// Else if call active
else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
isPhoneCalling = true;
}
// Else if call idle
else if (state == TelephonyManager.CALL_STATE_IDLE) {
if (isPhoneCalling) {
isPhoneCalling = false;
MyActivity.this.recreate();
}
}
}
}
This is my solution, it works perfectly on 4.3 - other OS versions not tested yet, but everything should be fine.
Registering the listener in MainActivity:
TelephonyManager tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
listener = new ListenToPhoneState();
tManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
The PhoneStateListener from MainActivty:
private class ListenToPhoneState extends PhoneStateListener {
private String LOG_TAG = "mainactivity";
private boolean isCallFinished = false;
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// wait for phone to go offhook (probably set a boolean flag) so
// you know your app initiated the call.
isCallFinished = true;
Log.i(LOG_TAG, "OFFHOOK");
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// when this state occurs, and your flag is set, restart your
// app
if (isCallFinished) {
isCallFinished = false;
Intent i = new Intent(getApplicationContext(),
MainActivity.class);
// this needs if you want some special action after the phone call
//ends, that is different from your normal lauch configuration
i.setAction("SHOW_PHONE_CALL_LIST");
startActivity(i);
finish();
}
Log.i(LOG_TAG, "IDLE");
}
}
}
I start the phone call from a fragment, but that doesn't make any difference:
Uri uri = Uri.parse("tel:" + Uri.encode(callIt));
Intent intent = new Intent(Intent.ACTION_CALL, uri);
startActivity(intent);
getActivity().finish();
You have to call finish() on the activity that starts the call, otherwise after the phone call, your app will stay behing the default Phone application.
When your app is starting, you can have a look at the intent, and you can set up your after call configuration. Call this in your onCreate() method:
if (intent.getAction().equals("SHOW_PHONE_CALL_LIST")) {
//perfom after call config here
}
I hope everything is clearly explained.
I think you must use a broadcast receiver and start the activity upon uphook. Also you need to declare permissions to read phone state.
Try to modify your code, that the important stuff is not in the onCreate() method but in the onResume() method, because when you come back from the phone call, the onCreate() method will not be triggered but the onResume() method. See http://developer.android.com/reference/android/app/Activity.html for more details on the Activity live cycle.
If that still does not help, use the flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
Try to use a context from the listener. Either the listener directly provides a context (so you can just call startActivity(…) or call getApplicationContext().startActivity(…)
In the end your code should something like this:
Intent intent = new Intent(RS_HomeScreenActivity.this,RS_HomeScreenActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
The solution is to launch an application with an extra included in bundle that says that app is launched as part of coming back from any other app.
When call ends, I launch an app using below code :
// Launch app
Intent i = new Intent(ActivityThatMadeCall.this,
LauncherActivity.class);
i.putExtra("EXTRA_RETURNED_FROM_CALL_APP", true);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
Then in my launcher activity I check for the extra and if it exists then start the activty that placed call. :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(getIntent().getExtras().getString("EXTRA_RETURNED_FROM_CALL_APP") != null) {
startActivity(new Intent(this, ActivityThatMadeCall.class));
}
}
I have an app that has a feature to launch an app, Pandora station, or shortcut. That all works fine. Later I want to stop the app I started. This works for most things except Pandora and Spotify don't always close. Sometimes they do but not always. It seems to be related to the current UI state. For instance, it works fine when I have Pandora showing or the home screen showing. When Home Dock or Car Mode is active it does not work. You can see all my source code here: http://code.google.com/p/a2dpvolume/
service.java is the file that has this functionality.
Here is the part of that code that tries to stop the music from playing and then stop the app.
if (bt2.hasIntent()) {
// if music is playing, pause it
if (am2.isMusicActive()) {
// first pause the music so it removes the notify icon
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
sendBroadcast(i);
// for more stubborn players, try this too...
Intent downIntent2 = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
KeyEvent downEvent2 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP);
downIntent2.putExtra(Intent.EXTRA_KEY_EVENT, downEvent2);
sendOrderedBroadcast(downIntent2, null);
}
// if we opened a package for this device, try to close it now
if (bt2.getPname().length() > 3 && bt2.isAppkill()) {
// also open the home screen to make music app revert to
// background
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
// now we can kill the app is asked to
final String kpackage = bt2.getPname();
CountDownTimer killTimer = new CountDownTimer(6000, 3000) {
#Override
public void onFinish() {
try {
stopApp(kpackage);
} catch (Exception e) {
e.printStackTrace();
Log.e(LOG_TAG, "Error " + e.getMessage());
}
}
#Override
public void onTick(long arg0) {
if (am2.isMusicActive()) {
// for more stubborn players, try this too...
Intent downIntent2 = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
KeyEvent downEvent2 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP);
downIntent2.putExtra(Intent.EXTRA_KEY_EVENT, downEvent2);
sendOrderedBroadcast(downIntent2, null);
}
try {
stopApp(kpackage);
} catch (Exception e) {
e.printStackTrace();
Log.e(LOG_TAG, "Error " + e.getMessage());
}
}
};
killTimer.start();
}
}
Here is the function stopApp().
protected void stopApp(String packageName) {
Intent mIntent = getPackageManager().getLaunchIntentForPackage(
packageName);
if (mIntent != null) {
try {
ActivityManager act1 = (ActivityManager) this
.getSystemService(ACTIVITY_SERVICE);
// act1.restartPackage(packageName);
act1.killBackgroundProcesses(packageName);
List<ActivityManager.RunningAppProcessInfo> processes;
processes = act1.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo info : processes) {
for (int i = 0; i < info.pkgList.length; i++) {
if (info.pkgList[i].contains(packageName)) {
android.os.Process.killProcess(info.pid);
}
}
}
} catch (ActivityNotFoundException err) {
err.printStackTrace();
Toast t = Toast.makeText(getApplicationContext(),
R.string.app_not_found, Toast.LENGTH_SHORT);
if (notify)
t.show();
}
}
}
Has someone else run into this problem? How can I reliably stop the launched app? I need to first get it to pause and put it in the background. That is the problem I am having. It works for most situations but not all. Some cases Pandora and Spotify will not respond to the key event being sent and they just keep playing. This keeps the notify icon active and makes the app a foreground activity so I can't stop it.
I finally figured out that Pandora does pause music when it sees a headset disconnect. So, I just had to send that disconnect intent so Pandora would pause. Once paused, it was able to be pushed to background and killed.
//Try telling the system the headset just disconnected to stop other players
Intent j = new Intent("android.intent.action.HEADSET_PLUG");
j.putExtra("state", 0);
sendBroadcast(j);
For anyone else trying this; The android.intent.action.HEADSET_PLUG intent is no longer allowed to be broadcast unless you are running as the system.
As the "HEADSET_PLUG" intent is now only supported if called by a system, I found app specific intents to be the way to go:
Intent pauseSpotify = new Intent("com.spotify.mobile.android.ui.widget.PLAY");
pauseSpotify.setPackage("com.spotify.music");
sendBroadcast(pauseSpotify);
Essentially, what this does, is it calls "PLAY" from the spotify app.
I got the idea from an article and applied it to normal android.