12adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi/* 22adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * Copyright (C) 2016 The Android Open Source Project 32adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * 42adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 52adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * you may not use this file except in compliance with the License. 62adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * You may obtain a copy of the License at 72adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * 82adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 92adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * 102adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * Unless required by applicable law or agreed to in writing, software 112adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 122adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * See the License for the specific language governing permissions and 142adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * limitations under the License 152adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi */ 162adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 172adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggipackage com.android.systemui.stackdivider; 182adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 19036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulianimport static com.android.systemui.stackdivider.ForcedResizableInfoActivity 20036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian .EXTRA_FORCED_RESIZEABLE_REASON; 21036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian 222adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport android.app.ActivityOptions; 232adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport android.content.Context; 242adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport android.content.Intent; 252adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport android.os.Handler; 26675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinsonimport android.os.UserHandle; 272adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport android.util.ArraySet; 28d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggiimport android.widget.Toast; 292adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 30d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggiimport com.android.systemui.R; 312adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport com.android.systemui.recents.events.EventBus; 322adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; 33675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinsonimport com.android.systemui.recents.events.component.ShowUserToastEvent; 34d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggiimport com.android.systemui.recents.misc.SystemServicesProxy; 35d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggiimport com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; 362adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport com.android.systemui.stackdivider.events.StartedDragingEvent; 372adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggiimport com.android.systemui.stackdivider.events.StoppedDragingEvent; 382adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 392adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi/** 402adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi * Controller that decides when to show the {@link ForcedResizableInfoActivity}. 412adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi */ 422adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggipublic class ForcedResizableInfoActivityController { 432adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 442adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private static final String SELF_PACKAGE_NAME = "com.android.systemui"; 452adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 462adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private static final int TIMEOUT = 1000; 472adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private final Context mContext; 482adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private final Handler mHandler = new Handler(); 49036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian private final ArraySet<PendingTaskRecord> mPendingTasks = new ArraySet<>(); 502adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private final ArraySet<String> mPackagesShownInSession = new ArraySet<>(); 512adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private boolean mDividerDraging; 522adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 532adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private final Runnable mTimeoutRunnable = new Runnable() { 542adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi @Override 552adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public void run() { 562adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi showPending(); 572adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 582adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi }; 592adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 60036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian /** Record of force resized task that's pending to be handled. */ 61036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian private class PendingTaskRecord { 62036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian int taskId; 63036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian /** 64036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or 65036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY} 66036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian */ 67036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian int reason; 68036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian 69036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian PendingTaskRecord(int taskId, int reason) { 70036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian this.taskId = taskId; 71036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian this.reason = reason; 72036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian } 73036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian } 74036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian 752adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public ForcedResizableInfoActivityController(Context context) { 762adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mContext = context; 772adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi EventBus.getDefault().register(this); 78d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi SystemServicesProxy.getInstance(context).registerTaskStackListener( 79d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi new TaskStackListener() { 80d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi @Override 81036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian public void onActivityForcedResizable(String packageName, int taskId, 82036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian int reason) { 83036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian activityForcedResizable(packageName, taskId, reason); 84d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi } 85d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi 86d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi @Override 87d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi public void onActivityDismissingDockedStack() { 88d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi activityDismissingDockedStack(); 89d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi } 90036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian 91036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian @Override 92036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian public void onActivityLaunchOnSecondaryDisplayFailed() { 93036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian activityLaunchOnSecondaryDisplayFailed(); 94036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian } 95d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi }); 962adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 972adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 982adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public void notifyDockedStackExistsChanged(boolean exists) { 992adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi if (!exists) { 1002adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mPackagesShownInSession.clear(); 1012adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1022adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1032adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1042adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public final void onBusEvent(AppTransitionFinishedEvent event) { 1052adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi if (!mDividerDraging) { 1062adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi showPending(); 1072adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1082adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1092adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1102adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public final void onBusEvent(StartedDragingEvent event) { 1112adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mDividerDraging = true; 1122adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mHandler.removeCallbacks(mTimeoutRunnable); 1132adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1142adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1152adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi public final void onBusEvent(StoppedDragingEvent event) { 1162adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mDividerDraging = false; 1172adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi showPending(); 1182adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1192adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 120036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian private void activityForcedResizable(String packageName, int taskId, int reason) { 121d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi if (debounce(packageName)) { 122d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi return; 123d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi } 124036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian mPendingTasks.add(new PendingTaskRecord(taskId, reason)); 125d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi postTimeout(); 126d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi } 127d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi 128d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi private void activityDismissingDockedStack() { 129675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson EventBus.getDefault().send(new ShowUserToastEvent( 130675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT)); 131d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi } 132d53f09254ed48365d3a5149d640437d76aed2e5dJorim Jaggi 133036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian private void activityLaunchOnSecondaryDisplayFailed() { 134036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian EventBus.getDefault().send(new ShowUserToastEvent( 135036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT)); 136036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian } 137036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian 1382adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private void showPending() { 1392adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mHandler.removeCallbacks(mTimeoutRunnable); 140036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian for (int i = mPendingTasks.size() - 1; i >= 0; i--) { 141036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i); 1422adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class); 1432adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi ActivityOptions options = ActivityOptions.makeBasic(); 144036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian options.setLaunchTaskId(pendingRecord.taskId); 145d5020c15b9bee33ecc63054450616cad928eec6aAndrii Kulian // Set as task overlay and allow to resume, so that when an app enters split-screen and 146d5020c15b9bee33ecc63054450616cad928eec6aAndrii Kulian // becomes paused, the overlay will still be shown. 147d5020c15b9bee33ecc63054450616cad928eec6aAndrii Kulian options.setTaskOverlay(true, true /* canResume */); 148036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.reason); 149675c5d8e5a6fd98e8324798e1ef31df20cee5b0fWinson mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); 1502adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 151036e3adce72b39ac5baefcf059891d6951206d81Andrii Kulian mPendingTasks.clear(); 1522adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1532adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1542adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private void postTimeout() { 1552adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mHandler.removeCallbacks(mTimeoutRunnable); 1562adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mHandler.postDelayed(mTimeoutRunnable, TIMEOUT); 1572adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1582adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1592adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi private boolean debounce(String packageName) { 1602adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi if (packageName == null) { 1612adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi return false; 1622adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1632adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi 1642adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that 1652adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi // triggers another notification. So ignore our own activity. 1662adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi if (SELF_PACKAGE_NAME.equals(packageName)) { 1672adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi return true; 1682adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1692adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi boolean debounce = mPackagesShownInSession.contains(packageName); 1702adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi mPackagesShownInSession.add(packageName); 1712adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi return debounce; 1722adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi } 1732adba07d75419462873dfeef40d4c983d832ed99Jorim Jaggi} 174