When you encounter a requirement at work, you need to hover over the entire application to display the control, with the target effect such as:
The first thought is the application of suspended window permissions, ok~ open search engine, not to see how to apply, but "android window rights of the various models of the system adaptation, Android bypass the right to display the suspended window ...", why the suspended window of the right to have so many pits it? Suspended windows can be displayed on the desktop, by malicious software used to secretly play ads what to do? As a special permission at the system level, this is what it should be proud of--
Correctly guide the user to open the Suspended window permission is the standard practice, if this is the conclusion of this article is not necessary to write, we bypass the suspended window rights directly to display, most of which is to optimize the user experience, not malicious. Sometimes we just want to implement the floating window in our own application, however, Andorid does not provide such a method, but also has to retreat to use the system-level suspended window permissions.
OK, now that you can bypass permission requests, redefine the requirements:
尽量绕过申请权限,实现在 app 指定界面显示悬浮控件,控件的位置不需要改变
How to bypass the suspended window permissions? Most of the online WindowManager add a type_toast type of control, as follows:
WindowManager windowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST; windowManager.addView(view, layoutParams);
The system does not require permissions by default when adding Type_toast type controls, so you can bypass the hover window permissions. But this approach is not suitable for all models, such as my pro-tested millet (MIUI8) and Nexus 7.1.1 model will be error Permission denial, need to apply for permission, this method may be possible, but now certainly not.
Abandon the Type_toast scheme, cannot add view to the window, that can only obediently apply permission? At this point you may want to add a view to all of the Activity's fixed positions, simulating the "hover" effect, such as the beginning of the article to achieve the effect, only to enter the new Activity to initialize the rotation angle, so that it is visually continuous line.
However, to consider a problem, when switching activity, the old activity's hover control is to be destroyed, the new activity of the suspension control is to be generated, that is, when switching activity, the floating control will disappear briefly, the activity The transition effect is set to fade, which can be achieved visually, but it is strictly limited by the Activity's switching effect. Is there any way to implement the visual continuity of the control when switching Activity? If you've ever used a shared element animation, you'll have an answer.
Where does the hover control add? In Baseactivity, you can also register the activity lifecycle callback for application, which is implemented below, adding a hover control for each activity in application:
Public class baseapplication extends application { @Override Public void onCreate() {Super. OnCreate (); Registeractivitylifecyclecallbacks (NewActivitylifecyclecallbacks () {@Override Public void onactivitystarted(Activity activity) {if(Findviewbyid (r.id.floating_view_id)! =NULL)return; View view = Layoutinflater.from (activity). Inflate (R.layout.floating_view,NULL); View.setid (r.id.floating_view_id);if(Build.VERSION.SDK_INT >= build.version_codes. LOLLIPOP) {view.settransitionname (activity.getstring (r.string.transitionname)); } windowmanager.layoutparams params =NewWindowmanager.layoutparams (); params.gravity = Gravity.top | Gravity.left; Activity.addcontentview (Mpopview, mlayoutparams);}//omit ...
Enable shared element animations when switching Activity:
new Intent(this, Main2Activity.class); View view = findViewById(R.id.floating_view_id); ifnull) { ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( this,view, getString(R.string.transitionName)); ContextCompat.startActivity(this, intent, options.toBundle()); }else{ startActivity(intent); }
This solves the problem of temporarily disappearing the hover control when switching Activity, and then, when adding a hover control, initializes the rotation angle to achieve the beginning of the article. But there is a big flaw in this way, first of all it is incompatible with Andorid 5.0, see 4.4 That 10% of the small partner, mm ~ The flaw is very large, followed by a fatal flaw, regardless of whether the hover control is set to INVISIBLE or transparent, as long as the control has been added, It will show up first when switching, which should be a BUG in the shared element animation itself.
ok~ abandon the shared element scheme, does it really go around requesting permission? Consider the type_toast scheme again, why does it fail? It should be that the system limits this type of control, treat Type_toast no longer skip check permission steps, but like Type_phone and so on, then why our TOAST can skip it? Isn't toast a view of the Type_toast type? Anyway, toast doesn't require permission, so try starting with a toast. ok~, the key word now is a custom toast.
View Toast class source code, there is a way to the front light:
/** * Set the view to show. * @see #getView */ publicvoidsetView(View view) { mNextView = view; }
Toast is a customizable view, which provides the possibility for a custom toast, but the display length can only be set to Length_short or length_long, we need an infinite length of time, no method implementation, unless the reflection of the strange recruit ~ AH ~ The following is implemented by reflection Full code for unlimited duration toast:
/** * Custom Toast, unlimited duration * can set display position size */Class Alwaysshowtoast {PrivateToast Toast;PrivateObject MTN;PrivateMethod Show;PrivateMethod Hide;Private intMwidth = WindowManager.LayoutParams.WRAP_CONTENT;Private intMheight = WindowManager.LayoutParams.WRAP_CONTENT; Public Fixedfloattoast(Context ApplicationContext) {toast =NewToast (ApplicationContext); } Public void Setview(View view,intWidthintHeight) {mwidth = width; Mheight = height; Setview (view); } Public void Setview(View view) {Toast.setview (view); INITTN (); } Public void setgravity(intGravityintXoffset,intYoffset) {toast.setgravity (Gravity, Xoffset, yoffset); } Public void Show() {Try{Show.invoke (MTN); }Catch(Exception e) {E.printstacktrace (); } } Public void Hide() {Try{Hide.invoke (MTN); }Catch(Exception e) {E.printstacktrace (); } }/** * Setting toast Parameters with reflection */ Private void INITTN() {Try{Field Tnfield = Toast.getclass (). Getdeclaredfield ("MTN"); Tnfield.setaccessible (true); MTN = Tnfield.get (toast); Show = Mtn.getclass (). GetMethod ("Show"); Hide = Mtn.getclass (). GetMethod ("Hide"); Field Tnparamsfield = Mtn.getclass (). Getdeclaredfield ("Mparams"); Tnparamsfield.setaccessible (true); Windowmanager.layoutparams params = (windowmanager.layoutparams) tnparamsfield.get (MTN); Params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; Params.width = Mwidth; Params.height = Mheight; Field Tnnextviewfield = Mtn.getclass (). Getdeclaredfield ("Mnextview"); Tnnextviewfield.setaccessible (true); Tnnextviewfield.set (MTN, Toast.getview ()); }Catch(Exception e) {E.printstacktrace (); } }}
With this custom toast, skip permission to display the hover window is very easy, theoretically compatible with any version, any model, because this is just a common toast, the system does not allow a toast to display the ~ however ... Pro-Test in Nexus7.1.1 and above does not display, under Android 4.4 can not accept touch events, on the Xiaomi part of the model can not change the location.
ok~ Compare these scenarios:
Scenario 1: Request permission
优点:实现简单,只要正确引导用户打开权限即可 缺点:部分机型默认禁用; 需权限不友好
Scenario 2: Adding each interface, sharing element transitions
优点:不需权限 缺点:较复杂,只适用于5.0以上,且悬浮控件不可隐藏(共享元素会闪显控件)
Solution 3:type_toast
优点:实现简单 缺点:小米(MIUI8)、7.1.1需要权限,4.4以下无法接受点击事件
Scenario 4: Customizing Toast
优点:大部分机型不需权限,实现简单 缺点:Nexus7.1.1及以上不显示,4.4以下无法接受点击事件,小米(MIUI8)及部分机型不可改变位置
In combination with my needs, my hover control doesn't need to change position, so the final choice is:
Final scenario: 7.0 following with custom toast, 7.1 and above to guide users to request permission
If your needs are also suitable for this scenario, let me tell you the good news that I have encapsulated this scenario as a directly callable library: Fixedfloatwindow, a fixed (stationary) float (window), can be easily used:
FixedFloatWindow fixedFloatWindow = new FixedFloatWindow(getApplicationContext()); fixedFloatWindow.setView(view); fixedFloatWindow.setGravity(Gravity.RIGHT | Gravity.TOP100150); fixedFloatWindow.show();// fixedFloatWindow.hide();
Finally, there is a problem to solve, we want to implement is the application of the hover control, this scenario application back to the background can still display on the desktop, how to control it? We can record the activity number of the current start, and whenever there is an activity stop, this number is reduced by 1, when this number is 0 indicates that the app is back to the background, then hide the suspended window, similar to this:
@Override publicvoidonActivityStarted(Activity activity) { mActivityNum++; if (isNeedShow(activity)) { show(); }else{ hide(); } } @Override publicvoidonActivityStopped(Activity activity) { mActivityNum--; if0) { hide(); } }
About the beginning of the implementation of the effect is to use this method, the suspension window control in the application display, the effect of the complete code see Fixedfloatwindow Library Sample example.
Fixedfloatwindow Library Address: Https://github.com/yhaolpz/FixedFloatWindow
Reference article:
Implementation of floating windows in Android application
Android Hover window permissions for each model system adaptation Daquan
Android does not need permission to display suspended windows, and also talk about the reverse analysis app
Break through the Xiaomi window control of the suspension-windows with no permissions required
Practice summary of In-app suspension controls for Android