On the audio and video calls in the process of minimizing the implementation of this function, similar articles on the network, but it seems to have not seen the clearer explanation, here because the project needs to achieve such a function, today I recorded it down, on the one hand for later use to facilitate their own access, On the one hand also give people who need to provide a train of thought, let everyone less detours. Here I also refer to some of the articles about the Android hover box, and then combined with their own understanding of the implementation of the possible method is not the best, but this may also be a feasible solution.
First, the implementation effect (GIF effect may not be particularly good to record)
Second, the realization of ideas
The implementation of this function is not difficult, here I split the realization of ideas for two steps: 1, Video call activity minimized. 2, the Video Call suspension box opens
The concrete idea is this: when the user clicks the Minimize button, minimizes our video call activity (then the activity is in the background state), removes the original activity in the video canvas (because I use the NetEase cloud letter, Here they can only allow a video canvas to exist, here to see if the situation should be removed, at the same time, a delay of hundreds of milliseconds, open the hover box, create a new video canvas and then dynamically add to the hover box, listen to the hover box touch event, let the hover box can be dragged and moved; If the user clicks on the hover box, remove the newly created video canvas in the hover box and re-adjust the video call activity in the background, and then add a new video canvas to the activity again. About the addition of the video canvas to remove the method, here to see the third-party SDK access, such as the use of NetEase Cloud Letter SDK, their methods are as follows (excerpt from their SDK documentation), that is, to remove the canvas I just need to pass in null on the line.
How is the 1.Activity implemented minimized?
Activity minimization may not have been heard, but as long as the posture is correct, it is very simple to implement because the activity itself has a movetasktoback (Boolean nonroot), and if we want to minimize it, Just call Movetasktoback (true) to pass in a true value, but here's the premise that you need to set the activity's startup mode to SingleInstance mode, two steps to get it done. ( Note: Here is a little bit of knowledge, that is, the activity is minimized after the return from the background back to the foreground will callback Onrestart () method )
@Override Public Boolean Movetasktoback (Boolean nonroot) { return super.movetasktoback (nonroot); }
2. How is the suspension box open?
Here I put the implementation of the suspension box in a service services, the suspension box to open the closure and service services binding to bind the connection, open the service is equivalent to open our suspension box, the Unbind service is equivalent to close off the suspension box, so as to achieve better control effect.
A. First, we declare a service class named Floatvideowindowservice:
public class Floatvideowindowservice extends Service { @Nullable @Override public ibinder Onbind (Intent Intent) { return new Mybinder (); } public class Mybinder extends Binder {public floatvideowindowservice GetService () { return floatvideowindowservice.this; } } @Override public void OnCreate () { super.oncreate (); } @Override public int Onstartcommand (Intent Intent, int flags, int startid) { return Super.onstartcommand ( Intent, flags, Startid); } @Override public void OnDestroy () { Super.ondestroy (); }}
B. Create a layout file for the suspension box alert_float_video_layout, here according to the needs to write, if just like I gif above, only need to hover the box to display the other side of the video canvas, then the layout file can be as follows: (where the Suspended box size I fixed to a length of 80DP , high 110dp,id for Small_size_preview LinearLayout is mainly a container, you can dynamically add view to the inside, that is, our video canvas)
<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= " Http://schemas.android.com/apk/res/android "xmlns:app=" Http://schemas.android.com/apk/res-auto "Android:layout_ Width= "Wrap_content" android:layout_height= "wrap_content" > <framelayout android:layout_width= "80DP" android:layout_height= "110DP" android:background= "@color/black_1f2d3d" > <linearlayout A Ndroid:id= "@+id/small_size_preview" android:layout_width= "Match_parent" android:layout_height= "match _parent "android:background=" @color/transparent "android:orientation=" vertical "/> </framel Ayout></linearlayout>
c. After the layout is defined, the next step is to do some initialization of the hover box, which we put in the OnCreate () life cycle of the service, because it only needs to be executed once. The initialization here mainly includes: the basic parameters of the suspension box (position, width and high), the Click event of the hover box and the touch event of the hover box (can drag the range), etc., the code comment is already very clear, look directly at the code, as follows:
Public class Floatvideowindowservice extendsService {PrivateWindowManager Mwindowmanager; PrivateWindowmanager.layoutparams Wmparams; PrivateLayoutinflater Inflater; Constant Private BooleanClickflag;//view private view mfloatinglayout;//Floating Layout privatelinearlayout smallsizepreviewlayout;//container parent layout @Nullable @Override Publicibinder onbind (Intent Intent) {return newMybinder ();} public class Mybinder extendsBinder { publicFloatvideowindowservice GetService () {return floatvideowindowservice.this; } } @Override public voidOnCreate () {Super. OnCreate (); Initwindow ();//Set the basic parameters of the suspension window (position, width and high) initfloating ();//The handling of the hover box click event} @Override public int onstartcommand (Intent Intent, int flags, intStartid) {return Super. Onstartcommand (Intent, flags, Startid);} @Override public voidOnDestroy () {Super. OnDestroy ();} /** * Set the basic parameters of the suspension box (position, Width high) */private voidInitwindow () {Mwindowmanager =(WindowManager) Getapplicationcontext (). Getsystemservice (context.window_service); wmparams = GetParams ();// Set the parameters of the suspended window//Hover window default display with the upper left corner as the starting coordinate wmparams.gravity = Gravity.left |gravity.top;//The start position of the suspended window, because the setting is starting from the upper left corner, so the upper left corner of the screen is x=0;y=0 wmparams.x =; wmparams.y =;//Get the container, through this inflater to get the hover window control Inflater =Layoutinflater.from (Getapplicationcontext ());//Gets the layout of the floating window view mfloatinglayout = Inflater.inflate (r.layout.alert _float_video_layout, NULL); Add a view of a suspended windowMwindowmanager.addview (Mfloatinglayout, wmparams);} Privatewindowmanager.layoutparams Getparams () {wmparams = newwindowmanager.layoutparams ();//Set window type the following variable 2002 is displayed in the screen area and 2003 can be displayed above the status bar Wmparams.type =WindowManager.LayoutParams.TYPE_TOAST;//settings can be displayed on the status bar Wmparams.flags = WindowManager.LayoutParams.FLAG_NOT_ FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;//Setting the hover window length-width data Wmparams.width =WindowManager.LayoutParams.WRAP_CONTENT; wmparams.height =WindowManager.LayoutParams.WRAP_CONTENT; returnWmparams;}
private voidinitfloating () {smallsizepreviewlayout =Mfloatinglayout.findviewbyid (R.id.small_size_preview);//Hover box Click event Smallsizepreviewlayout.setonclicklistener ( NewView.onclicklistener () {@Override public voidOnClick (View v) {//Click here to return to activity}}); Hover box Touch event, set hover box to drag smallsizepreviewlayout.setontouchlistener (newFloatinglistener ()); }//start touch coordinates, moving coordinates (relative to the upper left corner of the screen) private intMtouchstartx, Mtouchstarty, Mtouchcurrentx, mtouchcurrenty;//coordinates at the beginning and the coordinates at the end (relative to the coordinates of their own control) private intMstartx, Mstarty, mstopx, mstopy;
Determine if the hover window is moving, make a mark here to prevent the move after the click event to trigger the private Boolean ismove; Private class Floatinglistener implementsView.ontouchlistener {@Override public booleanOnTouch (View V, motionevent event) {int action =event.getaction (); switch(Action) { caseMotionEvent.ACTION_DOWN:isMove = False; mtouchstartx = (int) event.getrawx (); Mtouchstarty = (int) Event.getrawy (); MSTARTX = (int) Event.getx (); Mstarty = (int) event.gety (); break; caseMotionEvent.ACTION_MOVE:mTouchCurrentX = (int) event.getrawx (); Mtouchcurrenty = (int) Event.getrawy (); Wmparams.x + = Mtouchcurrentx-mtouchstartx; Wmparams.y + = Mtouchcurrenty- Mtouchstarty; Mwindowmanager.updateviewlayout (Mfloatinglayout, wmParams); Mtouchstartx = Mtouchcurrentx; mtouchstarty = Mtouchcurrenty; Break MotionEvent.ACTION_UP:mStopX = (int ) {Ismove = True Span style= "font-size:13px" > Ismove; } }}
D. After the suspension box has been successfully initialized and the relevant parameters are set, the next step is to add the video canvas to the hover box, so that we can see each other's video footage, as well as the service's oncreate This life cycle to complete this operation, here the video canvas to add the way to use the NetEase Cloud Letter SDK, the specific way to add depending on the different SDK , the code is as follows:
/** * Initialize Preview window * / private void Initsurface () { if (Smallrender = = null) { Smallrender = new Avchatsurf Aceviewrenderer (Getapplicationcontext ()); } Addintosmallsizepreviewlayout (Smallrender); } /** * Add Surfaceview to smallsizepreviewlayout * /private void Addintosmallsizepreviewlayout ( Surfaceview surfaceview) { if (surfaceview.getparent () = null) { ((viewgroup) surfaceview.getparent ()). Removeview (Surfaceview); } Smallsizepreviewlayout.addview (Surfaceview); Surfaceview.setzordermediaoverlay (True); }
E. We mentioned above to combine the binding and unbinding of service services with the opening and closing of a hover box, so since we have a hover box open in the OnCreate () method of the service, we should close the hover box in its OnDestroy () method, The essence of closing the hover box is to remove the associated view , then clear our video canvas and execute the following code in the OnDestroy () method of the service:
@Override public void OnDestroy () { Super. OnDestroy (); if (mfloatinglayout! = null) { //Remove Suspension window mwindowmanager.removeview (mfloatinglayout); } Clear the video canvas avchatmanager.getinstance (). Setupremotevideorender (account, NULL, FALSE, 0);}
F. The service is bound in Bindservice and StartService two, using different binding methods its life cycle will not be the same, it is known that we need to let the suspension box in the video call activity when the drop off, Then, of course, we should use bind to start the service, let his life cycle follow his opener, that is to follow the activity life cycle of opening it.
Intent = new Intent (this, floatvideowindowservice.class);//Turn on service display hover box Bindservice (Intent, mvideoserviceconnection, Context.bind_auto_create); Serviceconnection mvideoserviceconnection = new Serviceconnection () { @Override public Void onserviceconnected (componentname name, IBinder service) { //Get the Operation object of the service Floatvideowindowservice.mybinder Binder = (floatvideowindowservice.mybinder) service; Binder.getservice (); } @Override public void onservicedisconnected (componentname name) { } };
Three, the complete process
Now that we put the above mentioned in series, the idea will be more clear, if I am now in the video call, click the Video minimized button, we should follow the following steps in order: (If you are in the right position, it should be a hover box now)
public void Startvideoservice () { movetasktoback (true);//Minimize activity Intent = new Intent (this, Floatvideowindowservice.class);//Turn on service display hover box bindservice (Intent, mvideoserviceconnection, context.bind_auto_ CREATE); }
When we click on the hover frame, we can use startactivity (intent) to open our activity again, this time the video call activity will callback Onrestart () method, we in Onrestart () Life cycle unbind the suspended frame service and re-set the new video canvas to the activity
@Override protected void Onrestart () {Super. Onrestart (); Unbindservice (mvideoserviceconnection)///Do not display the suspension box//From the suspension window to re-set the canvas (judge is not connected) if (iscallestablished {//If connected, first clear all canvas Avchatui.clearallsurfaceview (Avchatui.getaccount ());//delay reloading the remote and local video canvas Mhandle r.postdelayed (New Runnable () {@Override public void run () {Avchatui.initallsurfaceview ( Avchatui.getaccount ()); }}, orelse {//If not connected, initialize all canvas Avchatui.initlargesurfaceview directly ( Imcache.getaccount ()); } }
It's been a long time since I wrote a blog, and it's probably a little messy ( ̄_ ̄| | |)
If you have any questions or have a better idea of implementation, please leave me a message ~
Contact information: [Email protected]
The realization of minimizing the suspension frame during the Android audio and video call (similar to the Android8.0 picture effect)