blob: db7996eed7f033834261365a2e750cf2608e76d7 [file] [log] [blame]
Jorim Jaggi2adba072016-03-03 13:43:39 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.stackdivider;
18
Gus Prevasab336792018-11-14 13:52:20 -050019import static com.android.systemui.stackdivider.ForcedResizableInfoActivity
20 .EXTRA_FORCED_RESIZEABLE_REASON;
Andrii Kulian036e3ad2017-04-19 10:55:10 -070021
Jorim Jaggi2adba072016-03-03 13:43:39 +010022import android.app.ActivityOptions;
23import android.content.Context;
24import android.content.Intent;
25import android.os.Handler;
Winson675c5d82016-08-23 17:12:22 -070026import android.os.UserHandle;
Jorim Jaggi2adba072016-03-03 13:43:39 +010027import android.util.ArraySet;
Jorim Jaggid53f0922016-04-06 22:16:23 -070028import android.widget.Toast;
Gus Prevasab336792018-11-14 13:52:20 -050029
Jorim Jaggid53f0922016-04-06 22:16:23 -070030import com.android.systemui.R;
Winson Chung2cf6ad82017-11-09 17:36:59 -080031import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chung67f5c8b2018-09-24 12:09:19 -070032import com.android.systemui.shared.system.TaskStackChangeListener;
Jorim Jaggi2adba072016-03-03 13:43:39 +010033
Evan Roskyaf9f27c2020-02-18 18:58:35 +000034import java.util.function.Consumer;
35
Jorim Jaggi2adba072016-03-03 13:43:39 +010036/**
37 * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
38 */
39public class ForcedResizableInfoActivityController {
40
41 private static final String SELF_PACKAGE_NAME = "com.android.systemui";
42
43 private static final int TIMEOUT = 1000;
44 private final Context mContext;
45 private final Handler mHandler = new Handler();
Andrii Kulian036e3ad2017-04-19 10:55:10 -070046 private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>();
Jorim Jaggi2adba072016-03-03 13:43:39 +010047 private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
Winson Chung67f5c8b2018-09-24 12:09:19 -070048 private boolean mDividerDragging;
Jorim Jaggi2adba072016-03-03 13:43:39 +010049
50 private final Runnable mTimeoutRunnable = new Runnable() {
51 @Override
52 public void run() {
53 showPending();
54 }
55 };
56
Evan Roskyaf9f27c2020-02-18 18:58:35 +000057 private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
58 if (!exists) {
59 mPackagesShownInSession.clear();
60 }
61 };
62
Andrii Kulian036e3ad2017-04-19 10:55:10 -070063 /** Record of force resized task that's pending to be handled. */
64 private class PendingTaskRecord {
65 int taskId;
66 /**
67 * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
68 * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}
69 */
70 int reason;
71
72 PendingTaskRecord(int taskId, int reason) {
73 this.taskId = taskId;
74 this.reason = reason;
75 }
76 }
77
Evan Roskyaf9f27c2020-02-18 18:58:35 +000078 public ForcedResizableInfoActivityController(Context context, Divider divider) {
Jorim Jaggi2adba072016-03-03 13:43:39 +010079 mContext = context;
Winson Chung2cf6ad82017-11-09 17:36:59 -080080 ActivityManagerWrapper.getInstance().registerTaskStackListener(
Winson Chung67f5c8b2018-09-24 12:09:19 -070081 new TaskStackChangeListener() {
Jorim Jaggid53f0922016-04-06 22:16:23 -070082 @Override
Andrii Kulian036e3ad2017-04-19 10:55:10 -070083 public void onActivityForcedResizable(String packageName, int taskId,
84 int reason) {
85 activityForcedResizable(packageName, taskId, reason);
Jorim Jaggid53f0922016-04-06 22:16:23 -070086 }
87
88 @Override
89 public void onActivityDismissingDockedStack() {
90 activityDismissingDockedStack();
91 }
Andrii Kulian036e3ad2017-04-19 10:55:10 -070092
93 @Override
94 public void onActivityLaunchOnSecondaryDisplayFailed() {
95 activityLaunchOnSecondaryDisplayFailed();
96 }
Jorim Jaggid53f0922016-04-06 22:16:23 -070097 });
Evan Roskyaf9f27c2020-02-18 18:58:35 +000098 divider.registerInSplitScreenListener(mDockedStackExistsListener);
Jorim Jaggi2adba072016-03-03 13:43:39 +010099 }
100
Winson Chung67f5c8b2018-09-24 12:09:19 -0700101 public void onAppTransitionFinished() {
102 if (!mDividerDragging) {
Jorim Jaggi2adba072016-03-03 13:43:39 +0100103 showPending();
104 }
105 }
106
Winson Chung67f5c8b2018-09-24 12:09:19 -0700107 void onDraggingStart() {
108 mDividerDragging = true;
Jorim Jaggi2adba072016-03-03 13:43:39 +0100109 mHandler.removeCallbacks(mTimeoutRunnable);
110 }
111
Winson Chung67f5c8b2018-09-24 12:09:19 -0700112 void onDraggingEnd() {
113 mDividerDragging = false;
Jorim Jaggi2adba072016-03-03 13:43:39 +0100114 showPending();
115 }
116
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700117 private void activityForcedResizable(String packageName, int taskId, int reason) {
Jorim Jaggid53f0922016-04-06 22:16:23 -0700118 if (debounce(packageName)) {
119 return;
120 }
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700121 mPendingTasks.add(new PendingTaskRecord(taskId, reason));
Jorim Jaggid53f0922016-04-06 22:16:23 -0700122 postTimeout();
123 }
124
125 private void activityDismissingDockedStack() {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700126 Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
127 Toast.LENGTH_SHORT).show();
Jorim Jaggid53f0922016-04-06 22:16:23 -0700128 }
129
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700130 private void activityLaunchOnSecondaryDisplayFailed() {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700131 Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
132 Toast.LENGTH_SHORT).show();
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700133 }
134
Jorim Jaggi2adba072016-03-03 13:43:39 +0100135 private void showPending() {
136 mHandler.removeCallbacks(mTimeoutRunnable);
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700137 for (int i = mPendingTasks.size() - 1; i >= 0; i--) {
138 PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i);
Jorim Jaggi2adba072016-03-03 13:43:39 +0100139 Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
140 ActivityOptions options = ActivityOptions.makeBasic();
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700141 options.setLaunchTaskId(pendingRecord.taskId);
Andrii Kuliand5020c12017-06-01 17:49:02 -0700142 // Set as task overlay and allow to resume, so that when an app enters split-screen and
143 // becomes paused, the overlay will still be shown.
144 options.setTaskOverlay(true, true /* canResume */);
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700145 intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.reason);
Winson675c5d82016-08-23 17:12:22 -0700146 mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
Jorim Jaggi2adba072016-03-03 13:43:39 +0100147 }
Andrii Kulian036e3ad2017-04-19 10:55:10 -0700148 mPendingTasks.clear();
Jorim Jaggi2adba072016-03-03 13:43:39 +0100149 }
150
151 private void postTimeout() {
152 mHandler.removeCallbacks(mTimeoutRunnable);
153 mHandler.postDelayed(mTimeoutRunnable, TIMEOUT);
154 }
155
156 private boolean debounce(String packageName) {
157 if (packageName == null) {
158 return false;
159 }
160
161 // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that
162 // triggers another notification. So ignore our own activity.
163 if (SELF_PACKAGE_NAME.equals(packageName)) {
164 return true;
165 }
166 boolean debounce = mPackagesShownInSession.contains(packageName);
167 mPackagesShownInSession.add(packageName);
168 return debounce;
169 }
170}