国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android6.0 固定屏幕功能實現方法及實例

2019-12-12 03:58:03
字體:
來源:轉載
供稿:網友

Android 固定屏幕功能

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

一、設置固定屏幕

我們先來看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,第一次mLockTaskModeTasks為空,會發送一個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 == -1) {     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; 

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

在固定屏幕后,如果我們啟動其他TaskRecord的Activity是不能啟動的,我們來看下這個原理。在startActivityUncheckedLocked函數中會調用isLockTaskModeViolation函數來判斷是否進一步的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函數,在新建一個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(); 

三、取消固定屏幕

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

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

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

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."); } 

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 贵阳市| 虎林市| 清水县| 平武县| 德令哈市| 荥阳市| 武功县| 翁源县| 林州市| 福贡县| 平昌县| 花垣县| 开原市| 平塘县| 基隆市| 阿荣旗| 昌乐县| 靖边县| 巴林右旗| 儋州市| 敖汉旗| 黑水县| 舟曲县| 商水县| 佳木斯市| 黑河市| 安康市| 雅安市| 图们市| 绥芬河市| 邯郸市| 玉树县| 蓬溪县| 盘山县| 札达县| 扶余县| 温州市| 嘉祥县| 柞水县| 尼木县| 星子县|