日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

Android6.0 开发中怎么实现一个固定屏幕功能

發(fā)布時(shí)間:2023/12/15 综合教程 24 生活家
生活随笔 收集整理的這篇文章主要介紹了 Android6.0 开发中怎么实现一个固定屏幕功能 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本篇文章給大家分享的是有關(guān)Android6.0 開發(fā)中怎么實(shí)現(xiàn)一個(gè)固定屏幕功能,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

Android 固定屏幕功能

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

一、設(shè)置固定屏幕

我們先來(lái)看SystemUI/src/com/Android/systemui/recents/ScreenPinningRequest.Java的代碼,這段代碼就是長(zhǎng)按home鍵出現(xiàn)幾個(gè)Activity,然后按了圖釘?shù)哪莻€(gè)按鈕。在這里直接調(diào)用了AMS的startLockTaskModeOnCurrent函數(shù)。

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

我們來(lái)看AMS的startLockTaskModeOnCurrent函數(shù),先調(diào)用ActivityStackSupervisor的topRunningActivityLocked獲取最前面的Activity,然后調(diào)用startLockTaskModeLocked函數(shù),參數(shù)是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); 
  } 
} 

我們?cè)賮?lái)看topRunningActivityLocked函數(shù),先從mFocusedStack中獲取最前面的Activity。如果沒(méi)有再遍歷所有的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函數(shù)中主要是調(diào)用了ActivityStackSupervisor的setLockTaskModeLocked函數(shù),下面我們來(lái)看這個(gè)函數(shù),我們的task不為null,第一次mLockTaskModeTasks為空,會(huì)發(fā)送一個(gè)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;//發(fā)送消息 
    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 
  } 
} 

我們?cè)賮?lái)看消息處理,在消息處理中主要調(diào)用了WMS的disableKeyguard函數(shù)。

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啟動(dòng)流程

在固定屏幕后,如果我們啟動(dòng)其他TaskRecord的Activity是不能啟動(dòng)的,我們來(lái)看下這個(gè)原理。在startActivityUncheckedLocked函數(shù)中會(huì)調(diào)用isLockTaskModeViolation函數(shù)來(lái)判斷是否進(jìn)一步的Activity的啟動(dòng)流程,我們來(lái)看下這個(gè)函數(shù),調(diào)用getLockedTaskLocked來(lái)看mLockTaskModeTasks(就是鎖定屏幕的那些Task),如果當(dāng)前的task就是當(dāng)前正在固定屏幕的task,直接return false就是可以繼續(xù)啟動(dòng)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; 
  } 
} 

我們?cè)賮?lái)看TaskRecord的setLockedTaskAuth函數(shù),在新建一個(gè)TaskRecord的時(shí)候會(huì)調(diào)用setIntent函數(shù),而setIntent函數(shù)又是在TaskRecord的構(gòu)造函數(shù)中調(diào)用的。我們來(lái)看這個(gè)函數(shù)mLockTaskAuth的值是根據(jù)mLockTaskMode來(lái)定的,而mLockTaskMode又是ActivityInfo傳入的,這個(gè)值是在PKMS解析AndroidManifest.xml的時(shí)候構(gòu)造的,默認(rèn)就是LOCK_TASK_LAUNCH_MODE_DEFAULT,而當(dāng)沒(méi)有白名單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()); 
} 

我們?cè)賮?lái)看isLockTaskModeViolation函數(shù)如下代碼,現(xiàn)在是task的mLockTaskAuth 是LOCK_TASK_AUTH_PINNABLE,而當(dāng)前處于固定屏幕,所以mLockTaskModeTasks不為null,最后返回true。那Activity啟動(dòng)流程就不能走下去了,那就是代表啟動(dòng)普通的Activity會(huì)被阻止。

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

三、取消固定屏幕

最后我們?cè)賮?lái)看看取消固定屏幕,取消屏幕會(huì)在PhoneStatusBar中取消,但是一定是要有虛擬鍵,原生就是這么設(shè)定的。最后調(diào)用了AMS的stopLockTaskModeOnCurrent函數(shù)。這個(gè)函數(shù)主要是調(diào)用了stopLockTaskMode函數(shù),這個(gè)函數(shù)中主要是調(diào)用了ActivityStackSupervisor的setLockTaskModeLocked函數(shù),之前在固定屏幕時(shí)也是調(diào)用了這個(gè)函數(shù),但是這里我們仔細(xì)看,其第一個(gè)參數(shù)為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); 
  } 
} 

我們來(lái)看下這個(gè)函數(shù),如果為空,現(xiàn)在調(diào)用getLockedTaskLocked獲取當(dāng)前固定屏幕的TaskRecord,然后調(diào)用removeLockedTaskLocked去除這個(gè)TaskRecord,如果還不為null,調(diào)用resumeTopActivitiesLocked啟動(dòng)下個(gè)Activity(一般也就是下個(gè)屏幕鎖定的TaskRecord的Activity)。
如果為空了,直接返回。但是在我們下次啟動(dòng)普通的Activity的時(shí)候就恢復(fù)正常了,因?yàn)閙LockTaskModeTasks已經(jīng)為空了。

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

四、沒(méi)有虛擬鍵如何取消屏幕固定

前面說(shuō)過(guò)如果沒(méi)有虛擬鍵就不能取消屏幕固定了,我們說(shuō)下幾種方式

1.使用am命令 am task lock stop可以調(diào)用am的stopLockTaskMode函數(shù)

2.另一種我們可以在Activity.java中修改代碼,比較長(zhǎng)按返回鍵調(diào)用AMS的stopLockTaskMode方法,下面就是實(shí)現(xiàn),Activity本身提供了stopLockTask就是調(diào)用了AMS的stopLockTaskMode方法

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

3.直接在Settings中對(duì)這項(xiàng)進(jìn)行置灰處理

在SecuritySettings會(huì)讀取security_settings_misc.xml文件然后加入相關(guān)perference,這其中就會(huì)有如下是屏幕固定相關(guān)的

<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讀取該文件之后,調(diào)用WMS的hasNavigationBar來(lái)看有沒(méi)有虛擬鍵(沒(méi)有虛擬按鍵到時(shí)候不能取消屏幕固定),如果沒(méi)有直接把Settings中這項(xiàng)置灰。

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

總結(jié)

以上是生活随笔為你收集整理的Android6.0 开发中怎么实现一个固定屏幕功能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人在线日韩 | 樱桃视频一区二区三区 | 日本午夜精品 | 51国产偷自视频区视频 | 在线观看波多野结衣 | 国产高清精品软件丝瓜软件 | 国产亚洲精品久久 | 大乳丰满人妻中文字幕日本 | 毛片久久久久 | 在线播放91灌醉迷j高跟美女 | 国产成人精品一区二区 | 少妇太紧太爽又黄又硬又爽 | 日本熟女毛茸茸 | 中国毛片在线观看 | 黄色wwwww| 欧美综合亚洲图片综合区 | 337p亚洲精品色噜噜狠狠 | 中文字幕一区二区三区四区不卡 | a级性生活视频 | 国产精品久久久久久久久久久新郎 | 97人妻一区二区精品视频 | 日韩怡红院| 99精品视频在线观看 | 色老头在线一区二区三区 | 一区不卡在线 | 男人的天堂欧美 | 国产精品视频免费播放 | 国产成人精品123区免费视频 | 久久影音先锋 | 日韩激情啪啪 | 免费观看黄色小视频 | a国产精品 | 国产肥老妇视频 | 亚洲人人爱 | 熟女一区二区三区视频 | 日韩无码精品一区二区三区 | 国产日批| 狠色综合7777夜色撩人 | 国产高清一区二区三区四区 | 人人精品久久 | 国产又粗又猛视频免费 | 久久久久亚洲精品中文字幕 | 国产一级久久 | 国产精品无码午夜福利 | 久操这里只有精品 | www黄色片| 樱桃国产成人精品视频 | 国产成人啪精品 | 免费精品| 欧美xxxxx牲另类人与 | 精品国产精品国产偷麻豆 | www.国产com | 免费一区二区视频 | 天天草天天草 | 日韩免费观看av | 日日爱网站 | 成人黄色激情 | 日韩三级欧美 | 狠狠干很很操 | 黄色xxxxxx| 免费在线观看高清影视网站 | 综合av | 超碰超碰超碰超碰 | 综合激情网五月 | 丝袜老师办公室里做好紧好爽 | 日本极品丰满ⅹxxxhd | 久久二 | 成年人视屏 | 久久精品日韩无码 | 欧美日韩精品在线播放 | 黄色男女网站 | www污网站 | 国产精品影音先锋 | 波多野结衣视频一区 | 亚洲图片偷拍区 | 在线观看第一页 | 欧美成人aa| 成人午夜影院 | 国产精品一区二区av | 操极品| 日本黄色免费在线观看 | 三年中文免费观看大全动漫 | 伊人久久大香线蕉成人综合网 | 午夜视频1000 | 亚洲欧洲日韩综合 | 国产aⅴ激情无码久久久无码 | 日韩无码精品一区二区 | 久草网站 | 久久xxxx | 色吧av | 亚洲精品综合精品自拍 | 天天操天天插天天干 | √8天堂资源地址中文在线 欧美精品在线一区二区 | 91午夜视频在线观看 | 国产精品久久久影院 | 免费观看亚洲视频 | 日本东京热一区二区 | 热久久国产 | 国产精在线 |