精华内容
下载资源
问答
  • 主要介绍了Android6.0 固定屏幕功能实现方法及实例的相关资料,需要的朋友可以参考下
  • android6.0在设置->安全->屏幕固定开启后,然后再长按home键出现最近的几个Activity可以选择一个图钉按钮就开启了屏幕固定功能。这篇文章主要介绍了Android6.0 屏幕固定功能的相关资料,感兴趣的朋友一起看看吧
  • 海外项目没有NavigationBar时,要过CTS必须要有屏幕固定功能,但是没有NavifationBar屏幕固定功能启用后无法取消此功能,以下为修改此问题代码,其中PhoneWindowManager文件搜索含有“Screen Pinning”注释位置处的...
  • 作者emilsjolander,源码StickyListHeaders,该源码实现了列表中固定屏幕顶部的列表功能,实现能够固定屏幕顶部的ListView Section Header. 当前section的header固定屏幕顶部,当滑动到其他section时,其他...
  •  一、设置中开启屏幕固定:  此功能在设置-安全中开启,不清楚以往的版本中是否支持就有已经有了此功能,但是Android4.4设置中到时没有发现此项。在Android 5.0发现了此项设置。刚一看到此项设置,就心想:“这...

    转载自 https://blog.csdn.net/u013656135/article/details/49741659

     一、设置中开启屏幕固定:  

        此功能在设置-安全中开启,不清楚以往的版本中是否支持就有已经有了此功能,但是Android4.4设置中到时没有发现此项。在Android 5.0发现了此项设置。刚一看到此项设置,就心想:“这是什么鬼!”。设置中的代码在SecuritySettings.java和ScreenPinningSettings.java中,代码量不多,Preference XML文件是security_settings_misc.xml:                

     
    1. if (Settings.System.getInt(getContentResolver(),

    2. Settings.System.LOCK_TO_APP_ENABLED, 0) != 0) {

    3. root.findPreference(KEY_SCREEN_PINNING).setSummary(

    4. getResources().getString(R.string.switch_on_text));

    5. }

        看到上面代码后,到\android5.1\frameworks\base\core\java\android\provider\Settings.java找到了LOCK_TO_APP_ENABLED,然后就发现这货被hide了,意思就说,在独立应用中是不能去设置此项的值的:    

     
    1. /**

    2. * Whether lock-to-app will be triggered by long-press on recents.

    3. * @hide

    4. */

    5. public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";

        之后,本想查看下这货是怎么写进数据库的,纵所周知,provider settings里面的东西一般都会写进数据库,而settings.db的文件是这里被创建的:            

    \android5.1\frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java

         按照介个意思,我想应该是会在这里写进数据库啊,然后就在DatabaseHelper.java搜索LOCK_TO_APP_ENABLED,但是没有找到,只能说,它不是在这里写进数据库的,无奈之下,再度查看ScreenPinningSettings.java中的相关代码:      

     
    1. private void setLockToAppEnabled(boolean isEnabled) {

    2. Settings.System.putInt(getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED,

    3. isEnabled ? 1 : 0);

    4. }

          Settings.System.putInt()方法有如下描述:      

     
    1. /**

    2. * Convenience function for updating a single settings value as an

    3. * integer. This will either create a new entry in the table if the

    4. * given name does not exist, or modify the value of the existing row

    5. * with that name. Note that internally setting values are always

    6. * stored as strings, so this function converts the given value to a

    7. * string before storing it.

    8. *

    9. * @param cr The ContentResolver to access.

    10. * @param name The name of the setting to modify.

    11. * @param value The new value for the setting.

    12. * @return true if the value was set, false on database errors

    13. */

    14. public static boolean putInt(ContentResolver cr, String name, int value) {

    15. return putIntForUser(cr, name, value, UserHandle.myUserId());

    16. }

         由此推断,settings.db数据库system table中本没有lock_to_app_enabled此项,而在开启screen pinning后,会向此表中写入lock_to_app_enabled的数据:    

         settings.db 在手机中的位置:/data/data/com.android.providers.settings/database/settings.db (需要root)。

        

        二、屏幕固定开启后视图的显示:

               在Android5.1 -Recents分析 中曾提到过screen pinning。从代码上看,screen pinning和 Recents绑定到了一块,效果图大致是这样的:

                 (图1)

        意思就说,在显示Recents的时候,如果screen pinning在设置中已开启,那么在Recents 视图中最上面的app 缩略图的右下角会有个图标。点击图标以后会出现如下提示界面:

          (图2)

        此时点击“知道了”就会固定到Recents中显示的对应应用界面。通过Android5.1 -Recents分析 可知图1中的提示图标是在TaskView,其ID为lock_to_app_fab。既然响应点击事件,就可以在TaskView.java中直接找到onClick()方法:  

     
    1. @Override

    2. public void onClick(final View v) {

    3. final TaskView tv = this;

    4. final boolean delayViewClick = (v != this) && (v != mActionButtonView);

    5. if (delayViewClick) {

    6. // We purposely post the handler delayed to allow for the touch feedback to draw

    7. postDelayed(new Runnable() {

    8. @Override

    9. public void run() {

    10. if (Constants.DebugFlags.App.EnableTaskFiltering && v == mHeaderView.mApplicationIcon) {

    11. if (mCb != null) {

    12. mCb.onTaskViewAppIconClicked(tv);

    13. }

    14. } else if (v == mHeaderView.mDismissButton) {

    15. dismissTask();

    16. }

    17. }

    18. }, 125);

    19. } else {

    20. if (v == mActionButtonView) {

    21. // Reset the translation of the action button before we animate it out

    22. mActionButtonView.setTranslationZ(0f);

    23. }

    24. if (mCb != null) {

    25. mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView));

    26. }

    27. }

    28. }

             其中mActionButtonView就是响应点击事件的view。图2显示的view的布局为:screen_pinning_request_text_area.xml,其中Button ID:screen_pinning_ok_button就是图2中显示的“知道了”。这部分view 在ScreenPinningRequest.java中被inflate。  

     
    1. private void inflateView(boolean isLandscape) {

    2. // We only want this landscape orientation on <600dp, so rather than handle

    3. // resource overlay for -land and -sw600dp-land, just inflate this

    4. // other view for this single case.

    5. mLayout = (ViewGroup) View.inflate(getContext(), isLandscape

    6. ? R.layout.screen_pinning_request_land_phone : R.layout.screen_pinning_request,

    7. null);

    8. // Catch touches so they don't trigger cancel/activate, like outside does.

    9. mLayout.setClickable(true);

    10. ...

    11. ...

    12. }

      inflate视图,但是图2中中view是如何显示出来的呢?源码中是通过callback一层层的回调来实现的,前面提到过图1中的view是在TaskView中,TaskView有内部接口,在响应了view的onClick方法以后会调用TaskView类内部的callback:          

     
    1. if (mCb != null) {

    2. mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView));

    3. }

      而TaskStackView视图包含TaskView视图,并实现了TaskView内部的callback,并在此调用自己的callback:   

     
    1. @Override

    2. public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) {

    3. // Cancel any doze triggers

    4. mUIDozeTrigger.stopDozing();

    5. if (mCb != null) {

    6. mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask);

    7. }

    8. }

      而RecentsView视图又包含TaskStackView视图,并实现TaskStackView的接口,RecentsView在此调用自己callback(onScreenPinningRequest):  

     
    1. @Override

    2. public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,

    3. final TaskStack stack, final Task task, final boolean lockToTask) {

    4. // Notify any callbacks of the launching of a new task

    5. if (mCb != null) {

    6. mCb.onTaskViewClicked();

    7. }

    8. ...

    9. if (lockToTask) {

    10. animStartedListener = new ActivityOptions.OnAnimationStartedListener() {

    11. boolean mTriggered = false;

    12. @Override

    13. public void onAnimationStarted() {

    14. if (!mTriggered) {

    15. postDelayed(new Runnable() {

    16. @Override

    17. public void run() {

    18. mCb.onScreenPinningRequest();

    19. }

    20. }, 350);

    21. mTriggered = true;

    22. }

    23. }

    24. };

    25. }

    26. ...

    27.  
    28. }

      到这里,callback回调还没有完,RecentsView的 RecentsViewCallbacks 接口被RecentsActivity实现: 

     
    1. @Override

    2. public void onScreenPinningRequest() {

    3. if (mStatusBar != null) {

    4. mStatusBar.showScreenPinningRequest(false);

    5. }

    6. }

        直到这里callback回调才算基本结束,mStatusBar是PhoneStatusBar类的实例对象,其showScreenPinningRequest方法:    

     
    1. public void showScreenPinningRequest(boolean allowCancel) {

    2. mScreenPinningRequest.showPrompt(allowCancel);

    3. }

        ScreenPinningRequest.java的showPrompt()方法:    

     
    1. public void showPrompt(boolean allowCancel) {

    2. clearPrompt();

    3. mRequestWindow = new RequestWindowView(mContext, allowCancel);

    4. mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

    5. // show the confirmation

    6. WindowManager.LayoutParams lp = getWindowLayoutParams();

    7. mWindowManager.addView(mRequestWindow, lp);

    8. }

        到这里,图2中的视图在响应了图1视图中的onClick事件以后就显示出来了。

     

    三、屏幕固定实现的功能:

        经过上面的分析可知,最终响应Button-screen_pinning_ok_button来实现屏幕固定的功能,代码自然在ScreenPinningRequest.java中:   

     
    1. @Override

    2. public void onClick(View v) {

    3. if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {

    4. try {

    5. ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();

    6. } catch (RemoteException e) {}

    7. }

    8. clearPrompt();

    9. }

        其中ActivityManagerNative.getDefault() 相当于 ActivityManagerService,所以直接在ActivityManagerService.java中查找startLockTaskModeOnCurrent()方法:   

     
    1. @Override

    2. public void startLockTaskModeOnCurrent() throws RemoteException {

    3. enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,

    4. "startLockTaskModeOnCurrent");

    5. long ident = Binder.clearCallingIdentity();

    6. try {

    7. ActivityRecord r = null;

    8. synchronized (this) {

    9. r = mStackSupervisor.topRunningActivityLocked();

    10. }

    11. startLockTaskMode(r.task);

    12. } finally {

    13. Binder.restoreCallingIdentity(ident);

    14. }

    15. }

    16. void startLockTaskMode(TaskRecord task) {

    17. final String pkg;

    18. synchronized (this) {

    19. pkg = task.intent.getComponent().getPackageName();

    20. }

    21. boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;

    22. if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {

    23. StatusBarManagerInternal statusBarManager = LocalServices.getService(

    24. StatusBarManagerInternal.class);

    25. if (statusBarManager != null) {

    26. statusBarManager.showScreenPinningRequest();

    27. }

    28. return;

    29. }

    30. long ident = Binder.clearCallingIdentity();

    31. try {

    32. synchronized (this) {

    33. // Since we lost lock on task, make sure it is still there.

    34. task = mStackSupervisor.anyTaskForIdLocked(task.taskId);

    35. if (task != null) {

    36. if (!isSystemInitiated

    37. && ((mStackSupervisor.getFocusedStack() == null)

    38. || (task != mStackSupervisor.getFocusedStack().topTask()))) {

    39. throw new IllegalArgumentException("Invalid task, not in foreground");

    40. }

    41. mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,

    42. "startLockTask");

    43. }

    44. }

    45. } finally {

    46. Binder.restoreCallingIdentity(ident);

    47. }

    48. }

        从代码中可看出,此功能的实现都管理activity 的stack 和 task。锁住stack 和 task 不让新的进来,就达到屏幕固定的目的,因为在这种情况下,不能为其他的activity准备stack和task。而取消此模式,有其对应的方法: 

     
    1. @Override

    2. public void stopLockTaskModeOnCurrent() throws RemoteException {

    3. enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,

    4. "stopLockTaskModeOnCurrent");

    5. long ident = Binder.clearCallingIdentity();

    6. try {

    7. stopLockTaskMode();

    8. } finally {

    9. Binder.restoreCallingIdentity(ident);

    10. }

    11. }

     

    四、在独立应用中屏幕固定模式又会怎样:

        首先,此功能是否支持在第三方应用里面实现呢?也许会考虑使用ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)

        来看看是否有相关的方法,但是ActivityManager.java中的相关接口都是hide的,不能被第三方应用使用:    

     
    1. /**

    2. * @hide

    3. */

    4. public void startLockTaskMode(int taskId) {

    5. try {

    6. ActivityManagerNative.getDefault().startLockTaskMode(taskId);

    7. } catch (RemoteException e) {

    8. }

    9. }

    10. /**

    11. * @hide

    12. */

    13. public void stopLockTaskMode() {

    14. try {

    15. ActivityManagerNative.getDefault().stopLockTaskMode();

    16. } catch (RemoteException e) {

    17. }

    18. }

        虽然ActivityManager类不让使用,但是Activity.java中却提供了相关方法(需要API>=21):  

     
    1. public void startLockTask() {

    2. try {

    3. ActivityManagerNative.getDefault().startLockTaskMode(mToken);

    4. } catch (RemoteException e) {

    5. }

    6. }

    7.  
    8. public void stopLockTask() {

    9. try {

    10. ActivityManagerNative.getDefault().stopLockTaskMode();

    11. } catch (RemoteException e) {

    12. }

    13. }

        于是在模拟器上测试了一下:

        

        这么看来,此功能算是支持第三方应用开启,并且还提供了一个放来来判断系统是否处于此模式:     

     
    1. /**

    2. * Return whether currently in lock task mode. When in this mode

    3. * no new tasks can be created or switched to.

    4. *

    5. * @see Activity#startLockTask()

    6. */

    7. public boolean isInLockTaskMode() {

    8. try {

    9. return ActivityManagerNative.getDefault().isInLockTaskMode();

    10. } catch (RemoteException e) {

    11. return false;

    12. }

    13. }

     

        而这也带来了思考的问题,当在设置中开启屏幕固定功能,并在Recents上固定某个应用的界面,那么这个应用的界面在onResume的时候是否需要使用isInLockTaskMode来做判断,从而做相应的处理? 这个就要看情况而定吧,我用自己前面瞎写的手电筒应用做测试,如果开启此模式,手电筒会出问题,这个跟我实现手电筒的代码有关系。

        问题又来了,在第三方应用中开启屏幕固定功能,提示界面又是如何显示出来的呢?这个就要回到前面提到的PhoneStatusBar.java,前面在Recents界面固定某个应用的界面是RecentsActivity中实现RecentsView内部接口并调用了PhoneStatusBar类中的showScreenPinningRequest(boolean allowCancel)方法。但是PhoneStatusBar类中还重写了一个父类的方法showScreenPinningRequest()。应用独立开启屏幕固定功能就会调用此方法:  

     
    1. @Override

    2. public void showScreenPinningRequest() {

    3. if (mKeyguardMonitor.isShowing()) {

    4. // Don't allow apps to trigger this from keyguard.

    5. return;

    6. }

    7. // Show screen pinning request, since this comes from an app, show 'no thanks', button.

    8. showScreenPinningRequest(true);

    9. }

    展开全文
  • Google从Android5.0开始新增了一个屏幕固定功能(设置--&gt;安全--&gt;屏幕固定),屏幕固定后只能同时长按Navigation bar上 的“back”和“Recent”键才能解除。实体键无法解除屏幕固定,这是Google默认...
    一,Android L 版本参考FAQ:
    
    1. Google从Android5.0开始新增了一个屏幕固定功能(设置-->安全-->屏幕固定),屏幕固定后只能同时长按Navigation bar上   的“back”和“Recent”键才能解除。实体键无法解除屏幕固定,这是Google默认设计。因为android5.0开始Google Compatibility Definition Document建议手机设备配置navigation bar。CTSVerifier会测试屏幕固定功能,若设备没有navigation bar会导致该测项fail。
    2. 没有配置navigationbar的Android 5.1及更新的设备需PASS CTS,有两种方案:
        1)Screen pining时动态show/hide navigationbar方式,前提是设备屏幕支持多点触控,因为要同时按下back和recent键才能unpining。 如需要这种方案,请提e-service至MTK申请“Android5.1屏幕固定CTS temp patch".该patch会在测试screen pining时动态显示/隐藏navigationbar.
        2)若设备屏幕是伪多点触控,也可以选择设备某个实体键长按或者短按来screen unpinning. 请参考SOLUTION A实现.  
    3. 没有配置navigationbar的Android 5.0设备需PASS CTS,可选择设备某个实体键长按或者短按来screen unpinning. 请参考SOLUTION A实现. 

    4. 如不过CTS认证,仅需拿掉屏幕固定这一功能,请SOLUTION B.

    https://onlinesso.mediatek.com/FAQ#/SW/FAQ13896 点击打开链接


    二,Android O 版本不带虚拟按键,长按Back键退出屏幕固定模式,修改记录如下:

    alps_o1_mp2_151_One\update\alps\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

    interceptKeyBeforeDispatching()方法中添加

    interceptKeyBeforeDispatching(){
    
    //add by start for  dismiss pinned lock task mode 
    else if( keyCode == KeyEvent.KEYCODE_BACK){
    if (((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) && !mHasNavigationBar) {
    if (!keyguardOn) {
            try {
            ActivityManager.getService().stopSystemLockTaskMode();
            } catch (RemoteException e) {
            android.util.Log.e(TAG, "Failed to stop app pinning");
            }
    }
    }                
    }
    //add by end
    }

    展开全文
  • android6.0 固定屏幕功能

    千次阅读 2016-09-19 10:38:32
    可能大家看到这个标题不知道是什么东西,我先说明下,android6.0在设置->安全->屏幕固定开启后,然后再长按home键出现最近的几个Activity可以选择一个图钉按钮就开启了屏幕固定功能。 屏幕固定开启后,屏幕只能固定...

    可能大家看到这个标题不知道是什么东西,我先说明下,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.");
            }




    
    
    展开全文
  • import android.app.ActivityManagerNative;  public void startLockTask() {//固定屏幕  if(!isInLockTaskMode()) {  try {  ActivityManagerNative.getDefault().startLockTaskMo...

    import android.app.ActivityManagerNative;
        public void startLockTask() {//固定屏幕
            if(!isInLockTaskMode()) {
                try {
                    ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();
                } catch (RemoteException e) {}
            }else {
                Toast.makeText(getApplicationContext(), "现在已是屏幕固定模式", Toast.LENGTH_SHORT).show();
            }
        }
        
        public void stopLockTask() {//取消固定屏幕
            if(isInLockTaskMode()) {
                try {
                    ActivityManagerNative.getDefault().stopLockTaskModeOnCurrent();
                } catch (RemoteException e) {}
            }else {
                Toast.makeText(getApplicationContext(), "现在不在屏幕固定模式,无法取消屏幕固定", Toast.LENGTH_SHORT).show();
            }
        }
        public boolean isInLockTaskMode() {//判断是否处于屏幕固定模式中
            try {
                return ActivityManagerNative.getDefault().isInLockTaskMode();
            } catch (RemoteException e) {
                return false;
            }
        }
     

    展开全文
  • 在前端开发中,又是会遇到实现页面中有个导航栏,页面滚动到导航栏位置时,导航栏固定在顶部。滚动回去,导航栏再恢复到页面中。 我们需要获取 : 1. 导航栏在页面中距离窗口顶部的高度 top 2. 时刻检测窗口滚动的...
  • Android 5.0 Screen pinning 屏幕固定功能

    千次阅读 2015-02-17 17:49:39
    屏幕固定是android 5.0 上的新功能 其Api介绍如下: 我说一点比较重要的吧,就是开了屏幕固定以后,通知栏和状态栏会隐藏,home键和recent键会失效(单端失效),然后还不准系统启动其他activity。 就是说 你只能在...
  • Unity屏幕永远保持为固定分辨率

    千次阅读 2020-07-25 18:36:49
    pc程序不管运行在什么分辨率下,永远保持16:9的比例,多出的屏幕就留黑边。你们可以改变当前显示器分辨率模拟不同分辨率下的软件运行情况,测试是否改的符合预期。
  • 我在实现安卓模拟点击屏幕固定位置时尝试了很多方法,碰了不少壁,现在我将我实现的方法分享给大家,以及我尝试过的方法也分享给大家,让大家在开发的路上少走些弯路。 首先我尝试用安卓辅助功能Accessibility...
  • Qt+pcl+vtk 屏幕选点

    2020-05-08 12:25:34
    本程序设计了Qt界面,实现了点云显示、屏幕选点、调节颜色等功能屏幕选点功能中,按住shift并选择相应的点,即可选中该点,目前功能并不完善,需要滑动滑块才能更新显示坐标。开发环境为vs2015+pcl1.8.1+Qt5.11.2+...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    虚拟控制台的切换可以通过按下Alt键和一个功能键来实现,通常使用F1-F6 。 例如,用户登录后,按一下“Alt+ F2”键,用户就可以看到上面出现的“login:”提示符,说明用户看到了第二个虚拟控制台。然后只需按“Alt+...
  • 13.ajax的步骤 什么是ajax? ajax(异步javascript xml) 能够刷新局部网页数据而不是重新加载整个网页。 如何使用ajax? 第一步,创建xmlhttprequest对象,var xmlhttp =new XMLHttpRequest();XMLHttpRequest对象用来...
  • Android固定屏幕

    2016-05-08 23:07:56
    屏幕固定是android 5.0 上的新功能 其Api介绍如下: 我说一点比较重要的吧,就是开了屏幕固定以后,通知栏和状态栏会隐藏,home键和recent键会失效(单独按会失效),然后还不准启动其他activity。 就是说 你只能在...
  • Flutter

    千次阅读 多人点赞 2019-09-27 11:00:21
    打包发布 四、flutter学习中的一些功能点的概要 状态管理、 五、flutter学习一些记录 1.0 colum 中包含tabBar 和tabBarView 出现页面白屏 通过给tabBar加固定高度和 tabBarView嵌套Expand解决; 目前不知道原因 ...
  • python游戏之愤怒的小鸟(一)

    千次阅读 2019-10-11 20:59:30
    ,未来有机会再深入,这里只对所用到的功能进行了解) 在使用之前我们明确几个概念: 刚体 :就是一个没有形状的物体,但是所有的物理性质:什么速度啊,碰撞什么的他都可以。 碰撞形状 :通过将形状附加到...
  • Labview做的屏幕截图

    2015-07-31 13:54:02
    Labview做的屏幕截图,调用一个dll文件,功能类似与PrtSc键功能
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...
  • 关于最新百度地图sdk如何使覆盖物固定屏幕(MapView)中心
  • 移动web开发笔记

    万次阅读 2016-05-15 20:12:27
    )搞清楚了PPI是什么意思,我们就能很容易理解PPI的计算方式了,我们需要首先算出手机屏幕的对角线等效像素,然后处以对角线(我们平常所说的手机屏幕尺寸就是说的手机屏幕对角线的长度),就可以得到PPI了。...
  • WPF开发教程

    万次阅读 多人点赞 2019-07-02 23:13:20
    定义一个系统后,下一步是将像素绘制到屏幕上。Visual 类用于生成可视化对象的树,每个对象可以选择性地包含绘制指令以及有关如何呈现这些指令(剪辑、变换等)的元数据。Visual 设计为极其轻量且灵活,所以大部分...
  • 红外线手持式额温枪方案开发

    千次阅读 2020-02-29 13:44:08
    壳有几个功能键,分别什么作用    2. 液晶屏需多少个脚    3. 传感器是数字的还是模拟    4. 产品规格:什么样的电池供电,家用还是医用,是否需要校准    四、产品生产测试    是否有黑体炉?...
  • 1.1-做了这么久,才知道什么是上位机

    万次阅读 多人点赞 2020-02-09 17:12:16
    通信API 在通信协议的基础上,具体发送什么数据即发送什么指令,还需要规定各个功能所对应的指令(上位机发给下位机的指令)。 每个功能所对应的指令叫做API(Application Programming Interface), 在实际工作中常...
  • SAP R3 功能详解 - 固定资产会计

    千次阅读 2014-09-29 21:35:11
    : 由总分类帐、 应收帐款和应付帐款、 固定资产、法定合 并以及特殊统计 会计功能组成; 金库模块 (TR) : 由现金管理、 金库管理和基金管理组成; 管理会计 (CO) :由一般费用成本核算、 生产成本核算...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,146
精华内容 39,658
关键字:

屏幕固定是什么功能