让 activity 始终处于堆栈顶部,或者在流氓应用程序启动活动时保持焦点?
Keep activity always on top of stack, or in focus when rogue apps launch activities?
我有一个全屏沉浸式 activity,它必须保持全屏直到用户明确退出。 (例如,想想全屏观看 Youtube 视频之类的事情)。
但是,我最近注意到启动许多不需要的活动可能会破坏我的应用程序的行为。例如,许多黑幕 "free apps" 倾向于生成全屏透明活动并显示广告,立即扰乱用户。 "Full screen" 来自某些实际上是全屏活动的应用程序的通知弹出窗口也会立即扰乱我的 activity。
有没有办法避免这些活动窃取焦点,或者有办法让它们隐藏在我的全屏模式后 activity 这样就不会破坏我的全屏模式?换句话说,当某个流氓应用程序决定在我的应用程序上启动 activity 时,我如何让我的 activity 始终保持在最前面?
不需要取消,但是"put behind for the moment"直到用户退出全屏activity。
我想到的一种方法是在失去焦点的那一刻用 FLAG_ACTIVITY_REORDER_TO_FRONT
重新启动我的 activity,但这对用户来说看起来不太漂亮:(
注意:如果您想自己尝试,我发现了一个可以启动这些流氓活动的应用程序。"simulates"。下载这个 - https://play.google.com/store/apps/details?id=com.nlucas.popupnotificationslite&hl=en
每当您收到通知时,它都会启动全屏透明 activity。尝试观看 Youtube 视频并收到来自某人的 10 条通知,想象一下这会有多让人分心。
更新:这样做似乎不起作用:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) {
Intent i = new Intent(getBaseContext(), MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
startActivity(i);
}
您可以 运行 后台服务经常检查,使您的应用程序保持在最前面:
public class ServiceKeepInApp extends Service {
//private static boolean sendHandler = false;
KeepInAppHandler taskHandler = new KeepInAppHandler(this);
@Override
public void onCreate() {
super.onCreate();
//sendHandler = true;
taskHandler.sendEmptyMessage(0);
}
@Override
public void onDestroy() {
super.onDestroy();
//sendHandler = false;
taskHandler.removeCallbacksAndMessages(0);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
private static class KeepInAppHandler extends Handler {
private final WeakReference<ServiceKeepInApp> mService;
private Context context;
private boolean sendHandler = false;
public KeepInAppHandler(ServiceKeepInApp mService) {
this.mService = new WeakReference<ServiceKeepInApp>(mService);
this.context = mService;
this.sendHandler = true;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
ActivityManager activityManager = (ActivityManager)context.getSystemService(Service.ACTIVITY_SERVICE);
if (activityManager.getRecentTasks(2, 0).size() > 0) {
if (activityManager.getRecentTasks(2, 0).get(0).id != GlobalVars.taskID) {
activityManager.moveTaskToFront(GlobalVars.taskID, 0);
}
if (sendHandler) {
sendEmptyMessageDelayed(0, 1000);
}
}
}
}
}
然后有一个单例class:
public static class GlobalVars {
public static int taskID;
public static Intent keepInApp;
}
然后在你的activity中:
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GlobalVars.taskID = getTaskId();
GlobalVars.keepInApp = new Intent(this, ServiceKeepInApp.class);
startService(GlobalVars.keepInApp);
}
}
您最好的选择是使用 "screen pinning"(如 here 所介绍,Android L 中的新功能)。任何其他都是不向前兼容的 hack 或解决方法。
坦率地说,Android 的设计并不是为了让应用无条件地完全接管设备。 Android 旨在成为响应用户愿望的工具。如果他们希望离开一个应用程序,那为什么要这么困难呢?此外,如果用户希望拥有意外启动活动的可疑应用程序,那就这样吧。每个人都按照系统制定的相同规则进行游戏。
我有一个全屏沉浸式 activity,它必须保持全屏直到用户明确退出。 (例如,想想全屏观看 Youtube 视频之类的事情)。
但是,我最近注意到启动许多不需要的活动可能会破坏我的应用程序的行为。例如,许多黑幕 "free apps" 倾向于生成全屏透明活动并显示广告,立即扰乱用户。 "Full screen" 来自某些实际上是全屏活动的应用程序的通知弹出窗口也会立即扰乱我的 activity。
有没有办法避免这些活动窃取焦点,或者有办法让它们隐藏在我的全屏模式后 activity 这样就不会破坏我的全屏模式?换句话说,当某个流氓应用程序决定在我的应用程序上启动 activity 时,我如何让我的 activity 始终保持在最前面?
不需要取消,但是"put behind for the moment"直到用户退出全屏activity。
我想到的一种方法是在失去焦点的那一刻用 FLAG_ACTIVITY_REORDER_TO_FRONT
重新启动我的 activity,但这对用户来说看起来不太漂亮:(
注意:如果您想自己尝试,我发现了一个可以启动这些流氓活动的应用程序。"simulates"。下载这个 - https://play.google.com/store/apps/details?id=com.nlucas.popupnotificationslite&hl=en
每当您收到通知时,它都会启动全屏透明 activity。尝试观看 Youtube 视频并收到来自某人的 10 条通知,想象一下这会有多让人分心。
更新:这样做似乎不起作用:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) {
Intent i = new Intent(getBaseContext(), MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
startActivity(i);
}
您可以 运行 后台服务经常检查,使您的应用程序保持在最前面:
public class ServiceKeepInApp extends Service {
//private static boolean sendHandler = false;
KeepInAppHandler taskHandler = new KeepInAppHandler(this);
@Override
public void onCreate() {
super.onCreate();
//sendHandler = true;
taskHandler.sendEmptyMessage(0);
}
@Override
public void onDestroy() {
super.onDestroy();
//sendHandler = false;
taskHandler.removeCallbacksAndMessages(0);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
private static class KeepInAppHandler extends Handler {
private final WeakReference<ServiceKeepInApp> mService;
private Context context;
private boolean sendHandler = false;
public KeepInAppHandler(ServiceKeepInApp mService) {
this.mService = new WeakReference<ServiceKeepInApp>(mService);
this.context = mService;
this.sendHandler = true;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
ActivityManager activityManager = (ActivityManager)context.getSystemService(Service.ACTIVITY_SERVICE);
if (activityManager.getRecentTasks(2, 0).size() > 0) {
if (activityManager.getRecentTasks(2, 0).get(0).id != GlobalVars.taskID) {
activityManager.moveTaskToFront(GlobalVars.taskID, 0);
}
if (sendHandler) {
sendEmptyMessageDelayed(0, 1000);
}
}
}
}
}
然后有一个单例class:
public static class GlobalVars {
public static int taskID;
public static Intent keepInApp;
}
然后在你的activity中:
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GlobalVars.taskID = getTaskId();
GlobalVars.keepInApp = new Intent(this, ServiceKeepInApp.class);
startService(GlobalVars.keepInApp);
}
}
您最好的选择是使用 "screen pinning"(如 here 所介绍,Android L 中的新功能)。任何其他都是不向前兼容的 hack 或解决方法。
坦率地说,Android 的设计并不是为了让应用无条件地完全接管设备。 Android 旨在成为响应用户愿望的工具。如果他们希望离开一个应用程序,那为什么要这么困难呢?此外,如果用户希望拥有意外启动活动的可疑应用程序,那就这样吧。每个人都按照系统制定的相同规则进行游戏。