In Android's many utility apps, the last app switcher is definitely a tool that lets people never unload. Las This application, its function is very simple, that is, through a floating button to achieve a key switch between two applications, but very practical, especially in the edge of the chat need to frequently switch applications. So you can see, want to develop a popular application, must pay attention to the user experience, as long as the user with the cool, function and then simple, it will be popular. So how simple is this function? Just come with me to make it happen.
I will not take screenshots, the following official screenshot to illustrate. Here really recommend the reader to download. Google Store download address: Last APP switcher development should be FQ it
Look at the original program interface:
You can see that the main interface is a series of switch options, and there is a floating circular window on the right side of the program. Below I will follow the steps to increase the function step by step.
Imitation iOS button
Writing demo does not need much good interface, but also can not be too ugly, the hand has a good look at the control directly dragged in use. Here is the effect chart, this set of buttons have several kinds, are imitation iOS, want to point to the original author of this blog, source GitHub address.
First, add a button that switches the main function:
Floating button
As you can see, the main function of this application is the red floating button. According to the program function, this floating button is created by the service opened by the program. Also because the activity of the program is destroyed after leaving the OnStart () state (for this reason), the button remains in its available state after that. So you can know that the service is started by StartService (). Next we need to write a service out, and then draw a floating button in the service. Specific details about the service reference to my previous blog: blog portal.
Write a service Floatbuttonservice, add a service to the Androidmanifest.xml file
<service android:name= ". Floatbuttonservice ">
</service>
Service to add a method of drawing floating buttons, see note
private void Createfloatview () {
}
method to create and destroy a floating button at the corresponding call location of the service
@Override
public void OnCreate () {
TODO auto-generated Method Stub
Super.oncreate ();
Createfloatview ();
}
@Override
public void OnDestroy () {
TODO auto-generated Method Stub
Super.ondestroy ();
if (mfloatlayout!= null) {
Mwindowmanager.removeview (mfloatlayout);
}
}
Additional permissions are required to use the floating buttons:
<uses-permission android:name= "Android.permission.SYSTEM_ALERT_WINDOW"/>
In this way, we can increase the response event for the button in the mainactivity, open and close the service.
to remove a program from the most recent task (last recent tasks)
Press the system navigation bar the third button we can see the most recently used task list, of course, the LAS switching program is here to choose the last two applications to switch. So it is necessary to remove your activity from the most recent tasks while switching.
As mentioned earlier, the Finishandremovetask () method deletes a task in the OnPause () state or OnStop () state of the activity. But this approach was introduced in API 21, Android 5.0. However, we also have a more convenient way to add to the <activity> tag of the config file
Android:excludefromrecents= "true"
So whether you press the back key or the home key, the program is removed from the most recently used task list.
switching between Tasks
Once you've removed your own activity from the most recent task list, consider getting the last two tasks and then switching to each other.
Adding in the Click event of a floating button
First you need to get the Activitymanager object
Activitymanager Mactivitymanager = (activitymanager) this.getsystemservice (Context.activity_service);
To get the task, you need the corresponding permissions
<uses-permission android:name= "Android.permission.GET_TASKS"/>
With permission, you can get to the task list.
list<activitymanager.recenttaskinfo> mapplist = new arraylist<activitymanager.recenttaskinfo> ();
Mapplist = Mactivitymanager.getrecenttasks (3, activitymanager.recent_ignore_unavailable);
Create a list of Recenttaskinfo with the Getrecenttasks method to get a list of the most recently used applications of the system.
With regard to the Getrecenttasks method, the first parameter is an integer value, the number of applications you need to return, but the actual number may be smaller than this value. Like what
I want to get 3, but only 1 in the background, then return only 1. The second parameter is the state of the application to return, I chose to ignore the unavailable application, should be completely off, not in the background of the application.
Again, this method is Android5.0 because of security problems, that is, android5.0 above version cannot use this method. So I saw in the App Store a while ago that the comments were Android5.0 with this no effect. Now I don't know, I do not have to study it. (Every time I say idle and then do basically is a pit--|)
The previous argument I'm going to choose 3 because I only need to get the last 2 apps, because every time you open a new application, the application information will be at the top of the list, so get the first 3.
But why 3 instead of 2, because the Android home interface is also an activity (should be), I can choose whether to ignore the home interface when switching. So considering home, you need to use 3.
The home package is named Com.android.launcher, based on which to judge.
private void getandstartintent (int i) {
Activitymanager.recenttaskinfo info = mapplist.get (i);
if (null = = info)
Toast.maketext (Floatbuttonservice.this, "No other apps", Toast.length_short). Show ();
else if (Sp.getboolean (Stringkey.excludehome, False)) {//If set True, do follow func
if (Info.baseIntent.getComponent (). Getpackagename (). Equals (Home_package))//exclude Home
Getandstartintent (2);
}else
Startactivitywithoutanimation (info);
}
The process of starting an application by default is to have a toggle animation, our program is used to switch programs, so cancel the start animation is a better choice.
Just add a flag to the intent you want to start (in some cases it will not take effect)
Intent.addflags (intent.flag_activity_no_animation);
power-on Boot
Android startup will send a boot_completed broadcast, we set up a broadcast receiver in the program to receive the broadcast, received a successful direct start service to display the floating button.
First set up a broadcast receiver Bootreceiver
public class Bootreceiver extends Broadcastreceiver {
@Override
public void OnReceive (context context, Intent Intent) {
TODO auto-generated Method Stub
if (Intent.getaction (). Equals ("Android.intent.action.BOOT_COMPLETED")) {//on BOOT
Intent a = new Intent (context, floatbuttonservice.class);
Context.startservice (a);
}
}
}
Registering a broadcast receiver under the,<application> tab in the configuration file
<receiver android:name= ". Bootreceiver ">
<intent-filter>
<action android:name= "Android.intent.action.BOOT_COMPLETED"/>
<category android:name= "Android.intent.category.LAUNCHER"/>
</intent-filter>
</receiver>
And then add permissions
<uses-permission android:name= "Android.permission.RECEIVE_BOOT_COMPLETED"/>
The boot is done. But how to use the switch to control whether the boot up?
sharedpreferences
With the switch to control the opening state of the function, this state can not be saved in the program, because the program is to be closed. Then it is to use some methods to save the state of the switch to the system, and then the service from the file read state, control their own program behavior. The best way to save configuration in Android is with Sharedpreferences. When I looked at the data files that Las applied, I found out that the output was actually the case.
Cat/data/data/com.abhi.lastappswitcher/shared_prefs/com.inpen.lastappswitcher.application_prefs.xml
<?xml version= ' 1.0 ' encoding= ' utf-8 ' standalone= ' yes '?>
<map>
<boolean name= "Com.inpen.lastAppSwitcher.PREF_SNAP_TO_EDGE" value= "true"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_LAND_HEIGHT" value= "/>"
<int name= "Com.inpen.lastAppSwitcher.PREF_LAND_FLOATER_Y" value= "485"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_LAND_WIDTH" value= "1280"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_PORT_FLOATER_Y" value= "776"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_PORT_WIDTH" value= "/>"
<boolean name= "Com.inpen.lastAppSwitcher.PREF_ERROR_MSG" value= "true"/>
<boolean name= "Com.inpen.lastAppSwitcher.PREF_STATUS_BAR_OVERLAY" value= "false"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_FLOATER_SIZE" value= "/>"
<int name= "Com.inpen.lastAppSwitcher.PREF_PORT_FLOATER_X" value= "765"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_PORT_HEIGHT" value= "1280"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_FLOATER_TRANSPARENCY" value= "/>"
<int name= "Currentquote" value= "6"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_SWITCHING_METHOD" value= "1"/>
<boolean name= "Com.inpen.lastAppSwitcher.PREF_FLOATER_MOVABLE" value= "true"/>
<boolean name= "Com.inpen.lastAppSwitcher.PREF_HAPTIC_FEEDBACK" value= "false"/>
<int name= "Com.inpen.lastAppSwitcher.PREF_FLOATER_COLOR" value= "0"/>
</map>
So, we can write sharedpreferences files according to our own needs.
Get an example of sharedpreferences first
Sharedpreferences sp = getsharedpreferences ("Las_demo", context.mode_private);
Parameter 1 is a filename without a suffix, obtaining an instance based on the filename, and the Sharedpreferences object of the same name obtains only the same instance;
Parameter 2 is mode operation mode:
Context.mode_private:
is the default mode of operation, which means that the file is private and can only be accessed by the application itself, in which case the written content overwrites the contents of the original file.
Context.mode_append:
The file you create is private, and the pattern checks for the existence of the file, appends it to the file, or creates a new file.
Mode_world_readable:
Indicates that the current file can be read by another application.
Mode_world_writeable:
Indicates that the current file can be written by another application.
After the instance is obtained, initialization is performed and some set values are written. Here because initialization only need once, but I did not find a way to determine whether the Sharedpreferences file exists (do not want to use file to check, this file exists system path, have permission problems, estimate not, have know can tell me), there is a public abstract Boolean contains (String key) method, but the feeling is not effective, so I added a key, to save the first created state, and then write another key-value, save.
if (!sp.getboolean (Stringkey.firstcreate, True)) {
Editor Editor = Sp.edit ();
Editor.putboolean (Stringkey.firstcreate, true);
Editor.putboolean (Stringkey.runatstart, false);
Editor.putboolean (Stringkey.snaptoedge, true);
Editor.putboolean (Stringkey.statusbaroverlay, false);
Editor.putboolean (Stringkey.excludehome, true);
Editor.commit ();
}
Set the key-value can be based on these values to set the button in the interface of the switch state and set the program's behavior.
if (Sp.getboolean (Stringkey.runatstart, False))
Mbtnrunatstartup.setchecked (TRUE);
Else
Mbtnrunatstartup.setchecked (FALSE);
Of course, when you manually change the state of a button, you also need to write a key back to the new value
Mbtnrunatstartup.setoncheckedchangelistener (New Oncheckedchangelistener () {
@Override
public void OnCheckedChanged (Compoundbutton buttonview, Boolean ischecked) {
TODO auto-generated Method Stub
if (ischecked)
Editboolkey (Stringkey.runatstart, true);
Else
Editboolkey (Stringkey.runatstart, false);
}
});
private void Editboolkey (String str, Boolean b) {
Editor Editor = Sp.edit ();
Editor.putboolean (str, b);
Editor.apply ();
}
When the Sharedpreferences Key-value is changed, the editor object instance needs to be obtained, and the setup completes with the Apply () method or the commit () method to submit the modification. If two editor instances are modified at the same time, the last commit is the same. If you do not care about the return value and use it in the main thread of the application, use apply () better than commit ().
At this point, the switch function is required to add a layer of the function to read the SP key value of the process, according to read the results of the decision function. is available.
the hover button appears above the status bar
According to the following settings WindowManager properties, there is no good explanation, put the document to see.
Wmparams.flags = Layoutparams.flag_not_touch_modal
| Layoutparams.flag_not_focusable
| Layoutparams.flag_layout_in_screen;
int Android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL = [0x20]
Window Flag:even When this window is focusable (it is not set), allow any pointer events outside of the "window" to be sen T to the windows behind it. Otherwise it would consume all pointer events itself, regardless of whether they are inside of the window.
int Android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE = 8 [0x8]
Window Flag:this window won ' t ever get key input focus, so the user can don't send key or other button events to it. Those would instead go to whatever focusable the window is behind it. This flag would also enable flag_not_touch_modal whether or not, is explicitly set.
Setting This is flag also implies that the window would not need to interact with a soft input method and so it would be z-ordered and positioned independently of any active input method (typically this means it gets z-ordered to top of the input Metho D, so it can use the ' full screen ' for its content and cover the ' input method if needed. can use Flag_alt_focusable_im to modify this behavior.
int Android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN = 256 [0x100]
Window flag:place the window within the entire screen, ignoring decorations around the border (a.k.a. The status bar). The window must correctly position its contents to take the "screen decoration into account." This flag was normally set for your by Window as described in Window.setflags.
Button Edge Adsorption effect
This should be the simplest, in the button touch event, when the move is over, the finger lift behavior action_up in the position to judge, if the button's x-coordinate in the left half of the screen, X set to 0, that is, the left edge of the screen displayed, on the contrary a truth.