2019年11月30日
キーワード:最近のアプリケーションリスト、SystemUI、Androidアプリケーションイベントインターセプタキル
Androidシステムは、「最近のアプリリスト」機能は、現在表示されているバックグラウンドで実行中のアプリケーションやプロセスの後半でトリガされます実行されています。ユーザーは即座に、アプリケーション・プロセスを殺すことができる、このリストにアプリケーションを切り替えることができます。
今日、私は需要を満たし:殺すために、アプリケーションホワイトリストができ、「最近のアプリケーションリスト」ではありませんアプリケーション「ホワイトリスト」機能を追加します。
言い換えれば、インターセプトアプリケーションイベントを殺します。
この関数は、SystemUI APKの最近のアプリケーションのリストです。APKは、複雑になることが、私は、「最近使ったアプリ一覧、」少しの機会、そして最終的にこのアプリケーションホワイトリストをタッチすると考えられ、数時間を過ごしました。
ポイントは、今記録する必要性を実現します、我々は他の学生が同じニーズを持って支援することを願っています。
また、著者は達成するために実行している需要Android5.1オペレーティングシステムrk3288開発ボードであることを言及。
まず、次のように示すコアアーキテクチャ図の最近のアプリケーションのリスト:
SystemUI APKはRecentsActivityの2セットを持っているようです。私たちは気にする必要があるcom.android.systemui.recentsは、下のパッケージ。
すべてRecentsViewビューコントロールを最初から。
レコードTaskView各アプリケーション処理対応は、次のように:
TaskStackViewの数は共通RecentsViewレイアウトにロードされている間、それは、TaskStackView上TaskViewの数が含まれています。
なぜいくつかのTaskStackViewそれはありますか?最近のAndroidアプリケーションのプロセスが行う記録されますので、これは「キャッシュ」。これは、あなたが最近適用された記録が記録されたデータは、最後のシャットダウン前に見つけることができ、システムを再起動した後に、レコードがキャッシュされるすべてのアプリケーションで使用するビューをクリックしてくださいものです。限り、我々はそれが私たちのより多くのTaskStackViewだけで罰金を傍受影響しないことを覚えているように、明確に表現するために、この単純な少し難しいです。
あなたは、コードを変更するために進むことができますので、まあ、我々は、フロントの基本的な理解を持っています。
私たちは、メインイベントをインターセプトする必要があり、2があります。
1、点击记录卡片右上角的关闭按钮事件;
2、滑动记录卡片事件;
其中滑动事件又可分为“左右滑动事件”与“上下滑动事件”。显然我们只能拦截“左右滑动”事件。
首先,我们要如何来区分哪个卡片是哪个应用呢?这些卡片默认是不记录与它相关的应用进程信息的。
./SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
在 boolean synchronizeStackViewsWithModel() 方法中。
这个方法比较长,但判断卡片与进程信息的关系的代码可不能随便加,笔者将完整代码贴出来:
1 boolean synchronizeStackViewsWithModel() { 2 if (mStackViewsDirty) { 3 RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); 4 SystemServicesProxy ssp = loader.getSystemServicesProxy(); 5 6 // Get all the task transforms 7 ArrayList<Task> tasks = mStack.getTasks(); 8 float stackScroll = mStackScroller.getStackScroll(); 9 int[] visibleRange = mTmpVisibleRange; 10 boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks, 11 stackScroll, visibleRange, false); 12 if (mDebugOverlay != null) { 13 mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]"); 14 } 15 16 // Return all the invisible children to the pool 17 mTmpTaskViewMap.clear(); 18 int childCount = getChildCount(); 19 for (int i = childCount - 1; i >= 0; i--) { 20 TaskView tv = (TaskView) getChildAt(i); 21 Task task = tv.getTask(); 22 int taskIndex = mStack.indexOfTask(task); 23 if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) { 24 mTmpTaskViewMap.put(task, tv); 25 } else { 26 mViewPool.returnViewToPool(tv); 27 } 28 } 29 30 // Pick up all the newly visible children and update all the existing children 31 for (int i = visibleRange[0]; isValidVisibleRange && i >= visibleRange[1]; i--) { 32 Task task = tasks.get(i); 33 TaskViewTransform transform = mCurrentTaskTransforms.get(i); 34 TaskView tv = mTmpTaskViewMap.get(task); 35 int taskIndex = mStack.indexOfTask(task); 36 37 if (tv == null) { 38 tv = mViewPool.pickUpViewFromPool(task, task); 39 40 if (mStackViewsAnimationDuration > 0) { 41 // For items in the list, put them in start animating them from the 42 // approriate ends of the list where they are expected to appear 43 if (Float.compare(transform.p, 0f) <= 0) { 44 mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpTransform, null); 45 } else { 46 mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpTransform, null); 47 } 48 tv.updateViewPropertiesToTaskTransform(mTmpTransform, 0); 49 } 50 } 51 52 try { 53 tv.setTag(null); 54 String pkg = task.key.baseIntent.getComponent().getPackageName(); 55 for(String pkg2 : RecentsActivity.whiteList) { 56 if(pkg2.equals(pkg)) { 57 tv.setTag(false); 58 break; 59 } 60 } 61 }catch(Exception e) { 62 e.printStackTrace(); 63 } 64 65 // Animate the task into place 66 tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex), 67 mStackViewsAnimationDuration, mRequestUpdateClippingListener); 68 69 // Request accessibility focus on the next view if we removed the task 70 // that previously held accessibility focus 71 childCount = getChildCount(); 72 if (childCount > 0 && ssp.isTouchExplorationEnabled()) { 73 TaskView atv = (TaskView) getChildAt(childCount - 1); 74 int indexOfTask = mStack.indexOfTask(atv.getTask()); 75 if (mPrevAccessibilityFocusedIndex != indexOfTask) { 76 tv.requestAccessibilityFocus(); 77 mPrevAccessibilityFocusedIndex = indexOfTask; 78 } 79 } 80 } 81 82 // Reset the request-synchronize params 83 mStackViewsAnimationDuration = 0; 84 mStackViewsDirty = false; 85 mStackViewsClipDirty = true; 86 return true; 87 } 88 return false; 89 }
上述代码第 52 行 ~ 第 63 行就是笔者用来判断关系的代码。需要强调的是:只能在那代码代码或它之后去判断。因为在这之前,卡片视图有可能还未实例化。
至于要如何记录卡片代表的进程信息,你们自由发挥即可。笔者这里是直接利用卡片View的 setTag() 方法。笔者直接将不能被杀掉的应用的卡片上保存一个 boolean 实例,可以杀的应用则是放空。这样待到后续通过点击卡片右上角的关闭按钮或者左右滑动时只需要简单地判断卡片视图的 getTag() 是否为空就行了。
点击右上角的关闭按钮的事件在哪呢?
./SystemUI/src/com/android/systemui/recents/views/TaskView.java
就在这个代码的 onClick() 方法中:
在上图红框处的代码就是笔者的拦截代码,只要不让它执行 dismissTask() 就不会杀掉这个进程。
滑动事件的流程要稍微复杂一点,但这里只讲核心部分:
./SystemUI/src/com/android/systemui/recents/views/SwiperHelper.java
在这个代码的 onTouchEvent() 方法中:
上图红框处是笔者的拦截处理代码。只要不让它执行红框代码后面的语句,应用记录卡片就不会左右方向滑动。