Why do I need to customize the lock screen page

As a mobile phone function existing in the era of black and white screen, lock screen still plays a huge role, especially with the advent of touch screen era, lock screen function has been played to the extreme. How many people have been bored every few minutes to open and close the lock screen, tireless, its acid is no less than pinching bubble film. Sure, a nice lock screen can make a phone look great, but there are three main purposes for lock screens: to protect your phone’s privacy, to prevent misoperation, and to save battery life without shutting down the system’s software. At present, the system lock screen of all kinds of phones can meet these needs, and it is very beautiful, so why do developers still need to build custom lock screen? Let’s imagine a scenario where a beautiful user is listening to a song on a music player. It takes several steps to change a song without the player’s custom lock screen (see the same article) : 1. Turn on the phone screen. 2. Unlock the lock screen. 3. Cut the song to screen out at this moment she estimates have been harassed square dance songs have 10 seconds, for 10 times, this is our programmers don’t want to see, so it is necessary to rely on our hands to build the flexible page from the music of the definition of the lock screen, will cut the song is compressed into two steps: light up the screen and cut song, by the way, can see the lyrics. Adding a switch to turn the custom lock screen on and off would be a perfect solution to users’ pain points.

Second, the basic principle of custom lock screen page

However, implementing a custom lock screen is a tedious task, as the system has 100 ways to make the non-native lock screen unusable. However, human intelligence is infinite, and programmers need to swim upstream. The idea of Android system is very simple, that is, when the App is started, start a service and listen to the broadcast of SCREEN_OFF. When the screen is off, the service listens to the broadcast, and start a lock screen and the Activity is displayed on the top of the screen. The Activity is created with the system lock screen removed (of course, you can’t disable it if you have a password). The schematic diagram is as follows:

It’s simple. What we need to talk about here are the details.

1. Broadcast registration

Service is a common Service. When an application is started, startService directly. You only need to use the same process as the application. SCREEN_OFF broadcast listeners must be registered dynamically. If registered statically in androidmanifest.xml, SCREEN_OFF broadcast listeners will not receive SCREEN_OFF broadcasts.The definitions of BroadcastReceiver are as follows:FLAG_ACTIVITY_NEW_TASK if you don’t Flag the Intent when you start an Activity, There will be a runtime exception “Calling startActivity() from outside of an Activity”, after all we are starting the Activity from a Service. An Activity must exist in a stack of activities, and a Service must not have a stack of activities when it starts an Activity, so it must create a new stack and load the started Activity. When using this flag, you also need to declare taskAffinity (the name of the new task) in the AndroidManifest, otherwise the screenclock Activity is essentially built into the task stack of the original App. The flag bit FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS is used to avoid activities started by a Service in the list of recently used programs, but it is not required and its use depends on the situation.

2. The Activity Settings

You should also configure the activity inside the locked screen so that the activity can be displayed even when the screen is locked and the system locked screen is removed. Of course, if the system lock screen password is set, there is no way to remove the system lock screen, here consider the case of no password set. The typical way to remove the lock screen is to use KeyguardManager, the code is as follows:Where, KeyguardManager is the lock screen management class, we get the instance object mKeyguardManager by getSystemService(), Call the newKeyguardLock() method of this object to get an instance of the inner KeyguardLock class mKeyguardLock of KeyguardManager. This method passes in a string argument identifying who hides the system lock screen. Finally, call the disableKeyguard() method of mKeyguardLock to cancel the system lock screen. The above method is no longer recommended and can be replaced with a better method. We can do exactly the same thing by setting the following flag bits in the onCreate() method of our custom screen-lock Activity:FLAG_DISMISS_KEYGUARD is used to remove a system lock screen page. FLAG_SHOW_WHEN_LOCKED enables your Activity to be displayed while the screen is locked. Of course, don’t forget to add the appropriate permissions in Manifest:

3. Mask buttons

When a custom lock screen does eventually appear on a phone, we want it to be like a system lock screen that can’t be touched by any key and can only be unlocked with a swipe or fingerprint, so it’s necessary to shield the keys to some extent. For phones that only have virtual buttons, we can partially solve this problem by hiding the virtual buttons, as described below. But when the user swipes at the bottom of the lock screen, the hidden virtual button still slides out, and must be masked if the user is using a physical button. The Back and Menu keys can be masked by overriding the onKeyDown() method:Click events for the Home button and the Recent button (which calls up the most recently opened app) are handled at the framework level, so neither onKeyDown nor dispatchKeyEvent can catch click events. There are a lot of information on the Internet about how to mask these two keys. Some use reflection, some change the flag bit and Type of Window, etc. In general, these methods only work for some Versions of Android, and some don’t compile at all. In fact, the purpose of doing so is nothing more than to achieve a pure lock screen page, but this approach is a bit gild the gild, easy to cause the lock screen page abnormal crash, we want to meet the user in the lock screen page fast operation, the Home button and Recent button is irrelevant, can completely ignore, less routine, more sincere.

4. Swipe to unlock the screen

After the above steps, when the screen goes off, we can open the screen again to see our custom lock screen, but at this time, even if the finger can not unlock. So, the next step is swipe unlock. Row bottle unlock the basic train of thought is very simple, when fingers sliding on the screen, slide intercept and handle events, make the lock screen page with finger movement, when the movement reaches a certain threshold, the user fingers fingers, automatic sliding to the border of the screen lock screen page disappear, if not reached threshold, automatically slide to the starting position, covering the screen again. To separate the swipe logic from the page content, we add a custom UnderView to the lock screen page layout. This UnderView fills the entire screen and sits below the lock screen content View (referred to as mMoveView and passed into the UnderView). All swipe related events are intercepted and processed here.MMoveView is the display content of the lock screen page. Except for some simple click events, other non-click events are handled by the underlying UnderView. Simply override UnderView’s onTouchEvent method to do this:MStartX records the x-coordinate at the start of the slide operation, handleMoveView controls the movement of mMoveView’s finger, and doTriggerEvent handles the animation of mMoveView’s movement after the finger leaves. The two methods are defined as follows:In handleMoveView(), the difference between the current contact x coordinate and the initial x coordinate mStartX is calculated moveX, and then the setTranslationX method of mMoveView is called to move. It’s worth noting that the setTranslationX method is currently only available on Android 3.0 or higher, and this is not an issue if you use the setTranslation method provided by the ViewHelper class in nineoldAndroid, an animation compatible library. ScrollTo and scrollBy can also move, but only the contents of the View, not the View itself. The other is to modify the layout parameter LayoutParams to move, although there is no version limit, relatively complicated to use. Here we use setTranslationX for brevity and for consistency with subsequent property animations. In addition, we can get the UnderView background with getBackground() and call setAlpha to change the opacity of the background based on the percentage of the screen that has been ripped off to make the drawer look like a light and shadow change.When the finger leaves the screen, the doTraiggerEvent method compares the sliding distance to the threshold, which is 0.4* screen width. If it falls below the threshold, the ObjectAnimator moves the mMoveView to its initial position at 0.25s. Update the background transparency in the onAnimationUpdate method of ObjectAnimator’s AnimatorUpdateListener. If it is below the threshold, move mMoveView off the right edge of the screen in the same way, and then kill the Activity by adding a listener to the AnimatorListenerAdapter. The listener’s onAnimationEnd method uses the mHandler defined in the Activity to send the Finish message to unlock the listener.

Transparent bar and immersion mode

Immersion mode and transparent bar are two different concepts, and for some reason, some domestic development or products confuse the two concepts. That’s ok, we’ll explain the difference between these two concepts in more detail and apply the two different modes to further improve the lock screen that is already taking shape.

1. Immersion mode

What is immersion mode? Starting with 4.4, Android has new flags “SYSTEM_UI_FLAG_IMMERSIVE” and “SYSTEM_UI_FLAG_IMMERSIVE_STIKY” for the “setSystemUiVisibility()” method, The Immersive Mode, called the “Immersive full-screen Mode,” lets your app hide the status bar and navigation bar for a truly full-screen experience. “SetSystemUiVisibility ()” to add two flags, i.e. “SYSTEM_UI_FLAG_FULLSCREEN”, SYSTEM_UI_FLAG_HIDE_NAVIGATION “(only for devices that use navigation bars, i.e. virtual buttons). There are some problems with both of these markers. For example, with the first marker, users cannot see the status bar unless the App provides a temporary exit from full-screen mode (for example, in some e-book software, the center of the screen is clicked once). This way, if the user wants to see what notifications are coming from the notification center, they have to tap the screen once to display the status bar before they can call up the notification center. The problem with the second tag is that Google thinks the navigation bar is so important to the user that it will be hidden for a short time. As soon as the user does something else, such as tap the screen once, the navigation bar is immediately brought up again. This isn’t a big problem for viewers, video apps, etc., but it’s almost a tragedy for apps like games where the user is constantly tapping the screen — which is why you couldn’t find a full-screen App that automatically hid the navigation bar before Android 4.4. The Immersive full-screen Mode, which was added after Android 4.4, allows users to call up the status bar and navigation bar briefly by swiping inward from the existing status bar/navigation area when the app is in Full Screen, without affecting the app’s Full Screen. The status bar and navigation bar will be semi-transparent and will be hidden automatically for a period of time or when the user interacts with the elements in the application. The four states of immersion mode are shown below. (refer towww.jcodecraeer.com/a/anzhuokai…)

State 1 represents the state of the page when the page is not in immersion mode. The Status Bar and Navigation Bar can still be seen. State 2 represents that when the user enters the immersion mode for the first time, the prompt popup window of the system tells the user how to call out the Status Bar and Navigation Bar in the immersion mode. State 3 represents immersion mode and you can see that the Status Bar and Navigation Bar are hidden. Status 4 indicates that the user calls the Status Bar and Navigation Bar in Sticky immersion mode. It can be seen that the two bars reappear but can be hidden automatically after a period of time. Generally speaking, only when the flags of immersion mode are combined with other flags related to Full Screen can we achieve the desired effect, that is, the operation logic displayed and hidden in status bar and navigation bar can be specified through the flags of immersion mode. Use other tabs to set the status bar and navigation bar to show or hide, and how it looks. These common flags and their corresponding functions are listed as follows:With so many tags, it can look confusing, but it’s easy and clear to use, and interested developers are free to test them out. Below, we use an example to apply these tags to the lock screen page to automatically hide the Navigation Bar while preserving the Status Bar. The code is very simple, using the Activity’s onCreate() method:SYSTEM_UI_FLAG_LAYOUT_STABLE keeps the View stable, so that the View does not do layout because of SystemUI changes. SYSTEM_UI_FLAG_IMMERSIVE_STIKY, which can automatically hide the bar again without related action when the hidden bar is called out (for example, by swiping up from the bottom edge of the screen); For SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, developers are easily confused by the HIDE_NAVIGATION. In fact, this Flag does not hide the navigation bar, but only controls the navigation bar to float on the top of the screen, does not occupy the screen layout space. “SYSTEM_UI_FLAG_HIDE_NAVIGATION” is the Flag that can hide the navigation bar. SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN does not hide the status bar, but floats above the screen. Note that this code needs to be added to the Activity’s OnCreate() method as well as to the overwritten onWindowFocusChanged() method, setting Flag again when the window gets focus, otherwise it may not achieve the desired effect.Also, be careful to set the fitsSystemWindows property to True on the outermost Layout in the Layout XML file if you don’t want your content to be pulled up to the Status bar. As follows:After setting the 5 flags above, the screen lock page effect picture is as follows:

Swipe your finger across the bottom of the screen and the Navigation Bar pops up, floats at the bottom of the lock screen and disappears automatically. The Status Bar also floats above, unhidden, as we expected.

2. Transparent bar

What is a transparent bar? In Android 4.4’s API description page, Google always refers to “system UI styling”, as a Translucent SYSTEM UI style. This “semi-transparency” includes the status bar and the notification bar. When developers make the application support for this new feature, the status bar and the navigation bar can be changed separately/simultaneously to a gradual translucent style, as shown below:

With the introduction of Material Design after Android 5.0, the status bar and navigation bar have become more varied. Now, in addition to the original “translucent” mode, there are “full transparent” mode and “color” mode, one can completely hide the background, another can take a color as the background color, the various types of transparent bar (transparent status bar above, transparent navigation bar below) :    So,The transparent bar only changes the color of the status bar and navigation bar. It does not hide the status bar and navigation bar as immersion mode does, but the two are fundamentally different. For Android 4.4 or later, you can set the transparent status bar as follows:For Android 5.0 or later, you can set the transparent status bar as follows:In addition to clearing 4.4’s FLAG_TRANSLUCENT_STATUS, the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_STABLE should also be used. We added flag_DRAWS_system_bar_BACKGROUND and called setStatusBarColor to set the color of the status bar to transparent. After a combination of immersion mode and transparent bar, the lock screen looks like this:

Four, fingerprint unlock

Up to now, our lock screen page has been basically completed, which can solve users’ pain points very elegantly, but there is no obvious difference with the current App custom lock screen page. The next step is to consider fingerprint unlocking, which is common on new phones.

1. The customized screen lock page cannot be unlocked through fingerprint identification

Hold fingerprint unlock the phone users in the use of custom App page lock screen will appear a confused, when you light the screen and be able to see the custom lock screen page, in the use of fingerprints unlock after successful model (partial fingerprint unlock operation can only lock screen page) in the system, custom lock screen page still exists, you still need to open a custom page lock screen, to see the phone home screen. A tricky solution to this problem is to listen for the ACTION_USER_PRESENT broadcast in the service of the lock page. ACTION_USER_PRESENT broadcast Is an ACTION_USER_PRESENT broadcast that is triggered when the system lock page is unlocked. If you finish the custom lock screen when receiving this broadcast, you can avoid the problem that the custom lock screen will still be displayed after the fingerprint is unlocked successfully. This approach requires that the FLAG_DISMISS_KEYGUARD flag that is configured when onCreate() is requested. This approach requires that the user dismiss_keyguard logically; this allows you to dismiss_keyguard easily if the user does not use that special password. ACTION_USER_PRESENT broadcast is triggered. After receiving the broadcast, the Service of the custom lock page sends finish broadcast to the custom lock page. As a result, the custom lock page just creates and finishes. Therefore, we must differentiate the scenario and process the received ACTION_USER_PRESENT broadcast only if there is a screen-lock password. Finish custom screen-lock page. Add the following code to the BroadcastReceiver onReceive() method:The isKeyguardSecure() method of the KeyguardManager object km is used to determine whether a screen-lock password has been set. NOTIFY_USER_PRESENT is a custom broadcast that notifies the screen-lock page Activity to call finish. This makes sense because if the screen lock password is not set, FLAG_DISMISS_KEYGUARD flag bit unlocks the system screen after it reaches the above block of code, isKeyguardSecure() returns false and does not cause the custom screen lock page Activity to be completed. If you do, FLAG_DISMISS_KEYGUARD does not unlock the system lock screen, and does not reach the block above, or finish. This avoids the dilemma of finishing the custom lock page as soon as it is created. On the other hand, any unlock that isn’t triggered in FLAG_DISMISS_KEYGUARD, such as fingerprint dismissals, makes the Activity disappear, satisfying the need.

2. The fingerprint identification on the customized lock screen cannot be used

In addition, in some mobile phone models, such as Xiaomi, fingerprint unlocking is invalid when the self-defined screen lock page covers the system screen lock page (with a screen lock password), that is, the self-defined screen lock page must be opened to unlock the fingerprint on the system screen lock page. To improve the experience, we can introduce the fingerprint unlock API to the Activity to recognize the fingerprint and unlock it. The code is as follows:Of course, don’t forget to add the appropriate permissions in Manifest:Before invoking the fingerprint recognition function, we need to determine whether the fingerprint recognition function is available and whether the APP has the corresponding permissions. This process is embodied in isFingerprintAuthAvailable (), the first step is to obtain KeyguardManager object, call isKeyguardSecure set () to determine whether a password lock screen, if any, will be expected to further judgment. CheckSelfPermission is used to determine whether the APP has permission for fingerprint recognition (required by SDK 23). If so, the FingerprintManager object is obtained and the isHardwareDetected() method of this object is called to determine whether the fingerprint recognition hardware is available. Invoke hasEnrolledFingerprints() to determine whether there are pre-registered fingerprints, and only if the above conditions are met can the fingerprint recognition function be invoked. Fingerprint identification of call in startFingerPrintListening () method, mainly is the call of FingerprintManager methodWhere, the crypto parameter represents the Wrapper class of crypto Objects in Android6.0, which can be used to make authenticate more secure or not. Here we set it to NULL. Cancel is used to cancel anthenticate(), we can just pass in a new object; Flags is the flag bit, set to 0. Callback is a fingerprint recognition callback, which contains the core method of fingerprint recognition: OnAuthenticationError () is the fingerprint matching consecutive callback after the failure (a few seconds before they can continue to match), onAuthenticationSucceeded () is the fingerprint matching success callback, OnAuthenticationFailed () is a callback when fingerprint matching fails. We do the corresponding processing in these methods, the onAuthenticationSucceeded () method call finish (), will be able to succeed in the fingerprint identification closed after the Activity.

Five, the summary

Through the above content to share, the goose hope to be able to help everyone’s development, if the content has a problem, also hope you give directions. To sum up, the implementation of custom lock screen page on Android is not a complicated thing, the key is to grasp some technical points to be relatively clear. The correct way to start an Activity in Service, the difference between broadcast static and dynamic registration, the distribution and propagation mechanism of touch events, the integrated use of transparent bar and immersion mode, and the application of new fingerprint recognition technology, all have a lot to be studied. When the author realized the custom lock screen page, he did not think too much. Sometimes he copied the practices of predecessors, sometimes he added various flags casually, and sometimes he confused the old and new APIS. Although the requirements were realized, the code was not simple enough and the readability was poor. Therefore, in the future development process, in addition to quickly realize the requirements, but also in the subsequent maintenance, a lot of thinking and research, so that the code can reach the “less line is not good, more line is uncomfortable” realm.