多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > android6.0 固定屏幕功能

android6.0 固定屏幕功能

來源:程序員人生   發布時間:2016-11-19 14:45:53 閱讀次數:2525次

可能大家看到這個標題不知道是甚么東西,我先說明下,android6.0在設置->安全->屏幕固定開啟后,然后再長按home鍵出現最近的幾個Activity可以選擇1個圖釘按鈕就開啟了屏幕固定功能。

屏幕固定開啟后,屏幕只能固定在設定的Task上的Activity切換。


1、設置固定屏幕

我們先來看SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java的代碼,這段代碼就是長按home鍵出現幾個Activity,然后按了圖釘的那個按鈕。在這里直接調用了AMS的startLockTaskModeOnCurrent函數。

@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(); }

我們來看AMS的startLockTaskModeOnCurrent函數,先調用ActivityStackSupervisor的topRunningActivityLocked獲得最前面的Activity,然后調用startLockTaskModeLocked函數,參數是TaskRecord。

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); } } } finally { Binder.restoreCallingIdentity(ident); } }
我們再來看topRunningActivityLocked函數,先從mFocusedStack中獲得最前面的Activity。如果沒有再遍歷所有的mStacks獲得。

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; }

在startLockTaskModeLocked函數中主要是調用了ActivityStackSupervisor的setLockTaskModeLocked函數,下面我們來看這個函數,我們的task不為null,第1次mLockTaskModeTasks為空,會發送1個LOCK_TASK_START_MSG消息

void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason, boolean andResume) { if (task == null) { // Take out of 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;//發送消息 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);//加入到mLockModeTasks中 if (task.mLockTaskUid == ⑴) { task.mLockTaskUid = task.effectiveUid; } if (andResume) { findTaskToMoveToFrontLocked(task, 0, null, reason);//把task放最前面 resumeTopActivitiesLocked();//顯示新的Activity } }

我們再來看消息處理,在消息處理中主要調用了WMS的disableKeyguard函數。

case LOCK_TASK_START_MSG: { // When 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); } } catch (RemoteException ex) { throw new RuntimeException(ex); } } break;



2、固定屏幕后Activity啟動流程

在固定屏幕后,如果我們啟動其他TaskRecord的Activity是不能啟動的,我們來看下這個原理。在startActivityUncheckedLocked函數中會調用isLockTaskModeViolation函數來判斷是不是進1步的Activity的啟動流程,我們來看下這個函數,調用getLockedTaskLocked來看mLockTaskModeTasks(就是鎖定屏幕的那些Task),如果當前的task就是當前正在固定屏幕的task,直接return false就是可以繼續啟動Activity的流程,而如果不是,我們需要看task的mLockTaskAuth變量。

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 can't be launched on top of locktask tasks. return !mLockTaskModeTasks.isEmpty(); default: Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth); return true; } }

我們再來看TaskRecord的setLockedTaskAuth函數,在新建1個TaskRecord的時候會調用setIntent函數,而setIntent函數又是在TaskRecord的構造函數中調用的。我們來看這個函數mLockTaskAuth的值是根據mLockTaskMode來定的,而mLockTaskMode又是ActivityInfo傳入的,這個值是在PKMS解析AndroidManifest.xml的時候構造的,默許就是LOCK_TASK_LAUNCH_MODE_DEFAULT,而當沒有白名單mLockTaskAuth最后就是LOCK_TASK_AUTH_PINNABLE。

void setLockTaskAuth() { if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { // Non-priv 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() ? 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() ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; break; } if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + " mLockTaskAuth=" + lockTaskAuthToString()); }

我們再來看isLockTaskModeViolation函數以下代碼,現在是task的mLockTaskAuth 是LOCK_TASK_AUTH_PINNABLE,而當前處于固定屏幕,所以mLockTaskModeTasks不為null,最后返回true。那Activity啟動流程就不能走下去了,那就是代表啟動普通的Activity會被禁止。

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


3、取消固定屏幕

最后我們再來看看取消固定屏幕,取消屏幕會在PhoneStatusBar中取消,但是1定是要有虛擬鍵,原生就是這么設定的。最后調用了AMS的stopLockTaskModeOnCurrent函數。這個函數主要是調用了stopLockTaskMode函數,這個函數中主要是調用了ActivityStackSupervisor的setLockTaskModeLocked函數,之前在固定屏幕時也是調用了這個函數,但是這里我們仔細看,其第1個參數為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); } } finally { Binder.restoreCallingIdentity(ident); } }

我們來看下這個函數,如果為空,現在調用getLockedTaskLocked獲得當前固定屏幕的TaskRecord,然后調用removeLockedTaskLocked去除這個TaskRecord,如果還不為null,調用resumeTopActivitiesLocked啟動下個Activity(1般也就是下個屏幕鎖定的TaskRecord的Activity)。

如果為空了,直接返回。但是在我們下次啟動普通的Activity的時候就恢復正常了,由于mLockTaskModeTasks已為空了。

void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason, boolean andResume) { if (task == null) { // Take out of 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; }


4、沒有虛擬鍵如何取消屏幕固定

前面說過如果沒有虛擬鍵就不能取消屏幕固定了,我們說下幾種方式

1.使用am命令 am task lock stop可以調用am的stopLockTaskMode函數

2.另外一種我們可以在Activity.java中修改代碼,比較長按返回鍵調用AMS的stopLockTaskMode方法,下面就是實現,Activity本身提供了stopLockTask就是調用了AMS的stopLockTaskMode方法

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

3.直接在Settings中對這項進行置灰處理

在SecuritySettings會讀取security_settings_misc.xml文件然后加入相干perference,這其中就會有以下是屏幕固定相干的

<PreferenceScreen android:key="screen_pinning_settings" android:title="@string/screen_pinning_title" android:summary="@string/switch_off_text" android:fragment="com.android.settings.ScreenPinningSettings"/>

我們可以在SecuritySettings讀取該文件以后,調用WMS的hasNavigationBar來看有無虛擬鍵(沒有虛擬按鍵到時候不能取消屏幕固定),如果沒有直接把Settings中這項置灰。

// Append the rest of the settings addPreferencesFromResource(R.xml.security_settings_misc); IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); try { boolean is_screen_pining = windowManager.hasNavigationBar(); root.findPreference(KEY_SCREEN_PINNING).setEnabled(is_screen_pining); } catch(RemoteException e) { Log.e("SecuritySettings", "get window service remoteException."); }






生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产毛片a级 | 亚洲欧美成人永久第一网站 | www.视频| 一本久到久久亚洲综合 | 国产成人精品一区二区三在线观看 | 18video性欧美19sex | 欧美视讯| 精品国产理论在线观看不卡 | 欧美伦理一区 | 亚洲嫩草影院在线观看 | 成人国产在线24小时播放视频 | 成人6969www色| 亚洲一区二区三区高清 不卡 | 人人澡人人擦人人免费 | 日本特黄的免费大片视频 | 欧美一区二区三区不卡免费 | 亚洲丶国产丶欧美一区二区三区 | 亚洲欧洲一区二区三区在线 | 亚州毛色毛片免费观看 | 国产成人精品区在线观看 | 羞羞影视 | 最近中文字幕免费mv视频 | 免费黄色福利 | 午夜伊人 | 羞羞动漫视频在线观看 | 亚洲免费毛片 | 手机在线看片国产 | 超级黄色毛片 | h免费看 | 国产区图片区小说区亚洲区 | 亚洲一逼 | 午夜视频你懂的 | 在线亚州 | 亚洲欧美国产精品久久久 | 日本护士xxxjapanese | 国产色综合一区二区三区 | 欧美日韩国产一区二区三区 | 国产精品一区二区久久不卡 | 国产精品久久现线拍久青草 | 亚洲淫欲 | 图片区偷拍区小说区 |