English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Android6Details of the fixed screen function

Maybe you don't know what this title is about, let me explain first, android6.0 in Settings->Security->After the screen is fixed, then long-press the home button to appear the recent several Activities, you can select a pin button to enable the screen fixed function.

After the screen is fixed, the screen can only switch between Activities on the set Task.

1. Set Fixed Screen

Let's take a look at SystemUI first/src/com/android/systemui/recents/The code in ScreenPinningRequest.java, this code is responsible for the appearance of several Activities when the home button is long-pressed, and then the button with the pin icon is pressed. Here, the startLockTaskModeOnCurrent function of AMS is directly called.

@Override 
public void onClick(View v) { 
if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) { 
try { 
ActivityManagerNative.getDefault().startLockTaskModeOnCurrent(); 
} catch (RemoteException e) {} 
} 
clearPrompt(); 
}

Let's look at the startLockTaskModeOnCurrent function of AMS, first call ActivityStackSupervisor's topRunningActivityLocked to get the front Activity, then call startLockTaskModeLocked function, with TaskRecord as the parameter.

public void startLockTaskModeOnCurrent() throws RemoteException { 
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, 
"startLockTaskModeOnCurrent"); 
long ident = Binder.clearCallingIdentity(); 
try { 
synchronized (this) { 
ActivityRecord r = mStackSupervisor.topRunningActivityLocked(); 
if (r != null) { 
startLockTaskModeLocked(r.task); 
} 
} 
} 
Binder.restoreCallingIdentity(ident); 
} 
}

Let's take a look at the topRunningActivityLocked function, first get the front Activity from mFocusedStack. If there is none, traverse all mStacks to get it.

ActivityRecord topRunningActivityLocked() { 
final ActivityStack focusedStack = mFocusedStack; 
ActivityRecord r = focusedStack.topRunningActivityLocked(null); 
if (r != null) { 
return r; 
} 
// Return to the home stack. 
final ArrayList<ActivityStack> stacks = mHomeStack.mStacks; 
for (int stackNdx = stacks.size()} - 1; stackNdx >= 0; --stackNdx) { 
final ActivityStack stack = stacks.get(stackNdx); 
if (stack != focusedStack && isFrontStack(stack)) { 
r = stack.topRunningActivityLocked(null); 
if (r != null) { 
return r; 
} 
} 
} 
return null; 
}

In the startLockTaskModeLocked function, it mainly calls the setLockTaskModeLocked function of ActivityStackSupervisor. Let's look at this function now. Our task is not null, and mLockTaskModeTasks is empty for the first time, a LOCK_TASK_START_MSG message is sent.

void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason, 
boolean andResume) { 
if (task == null) { 
// Exit lock task mode if necessary 
final TaskRecord lockedTask = getLockedTaskLocked(); 
if (lockedTask != null) { 
removeLockedTaskLocked(lockedTask); 
if (!mLockTaskModeTasks.isEmpty()) { 
// There are locked tasks remaining, can only finish this task, not unlock it. 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, 
"setLockTaskModeLocked: Tasks remaining, can't unlock"); 
lockedTask.performClearTaskLocked(); 
resumeTopActivitiesLocked(); 
return; 
} 
} 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, 
"setLockTaskModeLocked: No tasks to unlock. Callers=" + Debug.getCallers(4)); 
return; 
} 
// Should have already been checked, but do it again. 
if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) { 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, 
"setLockTaskModeLocked: Can't lock due to auth" 
return; 
} 
if (isLockTaskModeViolation(task)) { 
Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task."); 
return; 
} 
if (mLockTaskModeTasks.isEmpty()) { 
// First locktask. 
final Message lockTaskMsg = Message.obtain(); 
lockTaskMsg.obj = task.intent.getComponent().getPackageName(); 
lockTaskMsg.arg1 = task.userId; 
lockTaskMsg.what = LOCK_TASK_START_MSG;//Send message 
lockTaskMsg.arg2 = lockTaskModeState; 
mHandler.sendMessage(lockTaskMsg); 
} 
// Add it or move it to the top. 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "setLockTaskModeLocked: Locking to " + task + 
" Callers=" + Debug.getCallers(4)); 
mLockTaskModeTasks.remove(task); 
mLockTaskModeTasks.add(task);//Add it to mLockModeTasks 
if (task.mLockTaskUid == -1) { 
task.mLockTaskUid = task.effectiveUid; 
} 
if (andResume) { 
findTaskToMoveToFrontLocked(task, 0, null, reason);//Bring the task to the front 
resumeTopActivitiesLocked();//Display the new Activity 
} 
}

Let's take a look at the message handling, where the disableKeyguard function of WMS is mainly called.

case LOCK_TASK_START_MSG: { 
// When the lock task starts, we disable the status bars. 
try { 
if (mLockTaskNotify == null) { 
mLockTaskNotify = new LockTaskNotify(mService.mContext); 
} 
mLockTaskNotify.show(true); 
mLockTaskModeState = msg.arg2; 
if (getStatusBarService() != null) { 
int flags = 0; 
if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) { 
flags = StatusBarManager.DISABLE_MASK 
& (~StatusBarManager.DISABLE_BACK); 
} else if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) { 
flags = StatusBarManager.DISABLE_MASK 
& (~StatusBarManager.DISABLE_BACK) 
& (~StatusBarManager.DISABLE_HOME) 
& (~StatusBarManager.DISABLE_RECENT); 
} 
getStatusBarService().disable(flags, mToken, 
mService.mContext.getPackageName()); 
} 
mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG); 
if (getDevicePolicyManager() != null) { 
getDevicePolicyManager().notifyLockTaskModeChanged(true, 
(String)msg.obj, msg.arg1); 
} 
} 
throw new RuntimeException(ex); 
} 
}

Second, the Activity launch process after locking the screen

After locking the screen, if we start an Activity that cannot be launched from other TaskRecords, let's analyze the principle. In the startActivityUncheckedLocked function, the isLockTaskModeViolation function is called to determine whether to proceed with the Activity launch process. Let's analyze this function, which calls getLockedTaskLocked to look at mLockTaskModeTasks (those tasks locked on the screen), and if the current task is the task currently locked on the screen, we can directly return false to continue the Activity launch process. If not, we need to check the mLockTaskAuth variable of the task.

boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) { 
if (getLockedTaskLocked() == task && !isNewClearTask) { 
return false; 
} 
final int lockTaskAuth = task.mLockTaskAuth; 
switch (lockTaskAuth) { 
case LOCK_TASK_AUTH_DONT_LOCK: 
return !mLockTaskModeTasks.isEmpty(); 
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: 
case LOCK_TASK_AUTH_LAUNCHABLE: 
case LOCK_TASK_AUTH_WHITELISTED: 
return false; 
case LOCK_TASK_AUTH_PINNABLE: 
// Pinnable tasks cannot be launched on top of locktask tasks. 
return !mLockTaskModeTasks.isEmpty(); 
default: 
Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth); 
return true; 
} 
}

Let's take a look at the setLockedTaskAuth function of TaskRecord. When a new TaskRecord is created, the setIntent function is called, and the setIntent function is called in the constructor of TaskRecord. Let's look at this function, the value of mLockTaskAuth is determined by mLockTaskMode, and mLockTaskMode is passed in by ActivityInfo. This value is constructed when AndroidManifest.xml is parsed by PKMS, the default is LOCK_TASK_LAUNCH_MODE_DEFAULT, and when there is no whitelist, mLockTaskAuth is finally LOCK_TASK_AUTH_PINNABLE.

void setLockTaskAuth() { 
if (!mPrivileged && 
(mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || 
mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 
// Non-Privileged apps are not allowed to use always or never, fall back to default 
mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 
} 
switch (mLockTaskMode) { 
case LOCK_TASK_LAUNCH_MODE_DEFAULT: 
mLockTaskAuth = isLockTaskWhitelistedLocked() &63; 
LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 
break; 
case LOCK_TASK_LAUNCH_MODE_NEVER: 
mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 
break; 
case LOCK_TASK_LAUNCH_MODE_ALWAYS: 
mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 
break; 
case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 
mLockTaskAuth = isLockTaskWhitelistedLocked() &63; 
LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 
break; 
} 
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + 
" mLockTaskAuth=" + lockTaskAuthToString()); 
}

Let's take a look at the isLockTaskModeViolation function as follows. Currently, task's mLockTaskAuth is LOCK_TASK_AUTH_PINNABLE, and the current state is locked screen, so mLockTaskModeTasks is not null, and finally returns true. This means that the Activity startup process cannot proceed, indicating that launching a normal Activity will be blocked.

case LOCK_TASK_AUTH_PINNABLE: 
// Pinnable tasks cannot be launched on top of locktask tasks. 
return !mLockTaskModeTasks.isEmpty();

3. Cancel the locked screen

Finally, let's take a look at canceling the locked screen. The screen lock cancellation will occur in the PhoneStatusBar, but it must have a virtual key; this is how the original design is set. Finally, the AMS's stopLockTaskModeOnCurrent function is called. This function mainly calls the stopLockTaskMode function, which in turn mainly calls the ActivityStackSupervisor's setLockTaskModeLocked function. This function was also called when the screen was locked, but upon careful examination, the first parameter is null.

public void stopLockTaskMode() { 
final TaskRecord lockTask = mStackSupervisor.getLockedTaskLocked(); 
if (lockTask == null) { 
// Our work here is done. 
return; 
} 
final int callingUid = Binder.getCallingUid(); 
final int lockTaskUid = lockTask.mLockTaskUid; 
// Ensure the same caller for startLockTaskMode and stopLockTaskMode. 
// It is possible lockTaskMode was started by the system process because 
// android:lockTaskMode is set to a locking value in the application manifest instead of 
// the app calling startLockTaskMode. In this case {@link TaskRecord.mLockTaskUid} will 
// be 0, so we compare the callingUid to the {@link TaskRecord.effectiveUid} instead. 
if (getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED && 
callingUid != lockTaskUid 
&& (lockTaskUid != 0 
|| (lockTaskUid == 0 && callingUid != lockTask.effectiveUid))) { 
throw new SecurityException("Invalid uid, expected " + lockTaskUid 
+ " callingUid=" + callingUid + " effectiveUid=" + lockTask.effectiveUid); 
} 
long ident = Binder.clearCallingIdentity(); 
try { 
Log.d(TAG, "stopLockTaskMode"); 
// Stop lock task 
synchronized (this) { 
mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,) 
"stopLockTask", true); 
} 
} 
Binder.restoreCallingIdentity(ident); 
} 
}

Let's take a look at this function, if it is empty, now call getLockedTaskLocked to get the current fixed screen TaskRecord, then call removeLockedTaskLocked to remove this TaskRecord, and if it is not null, call resumeTopActivitiesLocked to start the next Activity (usually the next screen locked TaskRecord's Activity).

If it is empty, return directly. But it will return to normal when we start a normal Activity next time, because mLockTaskModeTasks is empty.

void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason, 
boolean andResume) { 
if (task == null) { 
// Exit lock task mode if necessary 
final TaskRecord lockedTask = getLockedTaskLocked(); 
if (lockedTask != null) { 
removeLockedTaskLocked(lockedTask); 
if (!mLockTaskModeTasks.isEmpty()) { 
// There are locked tasks remaining, can only finish this task, not unlock it. 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, 
"setLockTaskModeLocked: Tasks remaining, can't unlock"); 
lockedTask.performClearTaskLocked(); 
resumeTopActivitiesLocked(); 
return; 
} 
} 
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, 
"setLockTaskModeLocked: No tasks to unlock. Callers=" + Debug.getCallers(4)); 
return; 
}

IV. How to cancel the screen lock without a virtual key

As mentioned before, if there are no virtual keys, you cannot cancel the screen lock. Let's talk about several ways

1You can call the am's stopLockTaskMode function with the am command am task lock stop

2Another way we can modify the code in Activity.java is to call the AMS's stopLockTaskMode method by pressing the back key long. Below is the implementation, the Activity itself provides stopLockTask, which calls the AMS's stopLockTaskMode method

public boolean onKeyLongPress(int keyCode, KeyEvent event) { 
if (keyCode == KeyEvent.KEYCODE_BACK) { 
stopLockTask(); 
} 
return false; 
}

The above is what the editor introduces to everyone about Android6Detailed explanation of the fixed screen function of version 0.0, hoping it will be helpful to everyone. If you have any questions, please leave a message, and the editor will reply to everyone in time. We are also very grateful for everyone's support for the Niao tutorial website!

Statement: The content of this article is from the network, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously, and this website does not own the copyright, nor has it been manually edited, nor does it bear any relevant legal responsibility. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please replace # with @ when sending an email to report infringement, and provide relevant evidence. Once verified, this website will immediately delete the suspected infringing content.

You may also like