Jak*_*kob 8 service android overlay window view
我想创建一个Overlay,就像HUD一样,在我的应用程序活动堆栈(我的应用程序的任务)发生变化时驻留在屏幕上.
我找到了一些使用WindowManager的例子,但如果你愿意,我无法弄清楚正确的z-index的参数化.要么弱到下一个活动会覆盖我的叠加层,要么强大,叠加层是一个系统范围的叠加层,当应用程序移动到后台时也是可见的.
我的目标是在属于我的应用或任务的所有活动的顶部显示视图(应用程序将是首选).我知道应用程序和任务是android上的两个不同的东西......
我明确不想要的是使用需要android.permission.SYSTEM_ALERT_WINDOW的系统范围的窗口
---我的用例 -
我正在实现一个流程,其中包含一个为用户输入提供表单的活动.用户输入必须以相当复杂的方式处理,产生+/- 10个状态的可能结果.处理最多可能需要10分钟,具体取决于该过程的结果,我想显示相应的视图.在流程运行的过程中,我打算让用户保持更新但不允许他导航应用程序(除了中止流程).长期运行的每个可能结果将在不同的活动中呈现.
我很清楚,有几种可能的方法(例如只有一个活动).但是这个决定已经做出,并且超出了这个问题的范围.我已经实现了一个使用System Windows来显示覆盖的解决方案.为了隐藏覆盖,我必须依靠onStart,onStop事件并解释"App确实进入后台"和"App确实进入前景".这感觉很脏,我对这个解决方案不满意.我宁可退后一步,在调用活动的顶部显示我的叠加层,并在完成隐藏它的过程并向前移动到显示结果的活动时.
我尝试的另一件事是将视图从一个活动移动到另一个活动.但这显示了我不喜欢的动画的一些闪烁和中断.
如果我们能够专注于是否可以在应用程序/任务窗口之上而不是在系统或活动窗口内显示视图的问题,我将不胜感激;)
Ran*_*ndy 11
你真的只有两个选择.
1)您可以使用Theme.Dialog主题创建活动.这将在窗口顶部显示一个弹出窗口.您可以将对话框创建为无模态(可以单击).在我的快速测试中,我无法覆盖到我的屏幕边缘,虽然可能修改主题会解决这个问题.
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button test = (Button) this.findViewById(R.id.test);
test.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Button) v).setBackgroundColor(Color.RED);
}
});
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
}
}
Run Code Online (Sandbox Code Playgroud)
SecondActivity.java
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_main);
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
window.setGravity(Gravity.BOTTOM);
}
@Override
public void onBackPressed() {
//Override to prevent back button from closing the second activity dialog
}
}
Run Code Online (Sandbox Code Playgroud)
表现
....
<activity
android:name="com.example.control.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.control.SecondActivity"
android:theme="@android:style/Theme.Dialog"
android:label="@string/app_name" >
....
</activity>
....
Run Code Online (Sandbox Code Playgroud)
2)第二个选项是使用SYSTEM_ALERT_WINDOW.我更喜欢这种方法.你是正确的,它是可见的,并在每个其他应用程序之上,但是,你可以控制何时可见,何时不可见.我不会发布任何源代码,但我会给你一个总的攻击计划.
创建服务时,使用AIDL绑定到该服务.通过这种方式,您可以直接与服务对话,告诉它何时"隐藏"和"显示"叠加层.说到隐藏和显示,onPause和onResume可以用来告诉服务隐藏和显示叠加层.最后,如果您需要在叠加层上接收点击事件,那将证明是棘手的,因为触摸事件并不总是按照您期望的方式行事.
祝好运.
我认为您将对以下内容感兴趣.你不会要求android.permission.SYSTEM_ALERT_WINDOW.代码适用于Application类.
评论应该有助于您理解逻辑.代码应该开箱即用.
public class YourApplication extends Application {
// Popup to show persistent view
PopupWindow pw;
// View held by Popup
LinearLayout ll;
@Override
public void onCreate() {
super.onCreate();
// Register for Activity Lifecyle Callbacks
registerActivityLifecycleCallbacks(new YourCallBack());
// Initialize the view
ll = new LinearLayout(this);
ll.setLayoutParams(new LayoutParams(100, 100));
ll.setBackgroundColor(Color.BLUE);
// Initialize popup
pw = new PopupWindow(ll, 100, 100);
// Set popup's window layout type to TYPE_TOAST
Method[] methods = PopupWindow.class.getMethods();
for(Method m: methods){
if(m.getName().equals("setWindowLayoutType")) {
try{
m.invoke(pw, WindowManager.LayoutParams.TYPE_TOAST);
}catch(Exception e){
e.printStackTrace();
}
break;
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
if (pw != null && pw.isShowing()) {
pw.dismiss();
}
};
private final class YourCallBack implements ActivityLifecycleCallbacks {
int numOfRunning = 0;
@Override
public void onActivityCreated(Activity arg0, Bundle arg1) { }
@Override
public void onActivityDestroyed(Activity arg0) { }
@Override
public void onActivityPaused(Activity arg0) {
// An activity has been paused
// Decrement count, but wait for a certain
// period of time, in case another activity
// from this application is being launched
numOfRunning--;
// Delay: 100 ms
// If no activity's onResumed() was called,
// its safe to assume that the application
// has been paused, in which case, dismiss
// the popup
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (numOfRunning == 0) {
pw.dismiss();
}
}
}, 100L);
}
@Override
public void onActivityResumed(Activity arg0) {
// If no activities were running, show the popup
if (numOfRunning == 0) {
pw.showAtLocation(ll, Gravity.BOTTOM, 0, 0);
}
// Now, one activity is running
numOfRunning++;
}
@Override
public void onActivitySaveInstanceState(Activity arg0, Bundle arg1) { }
@Override
public void onActivityStarted(Activity arg0) { }
@Override
public void onActivityStopped(Activity arg0) { }
};
}
Run Code Online (Sandbox Code Playgroud)