1/* 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 19import android.app.ActivityOptions; 20import android.content.Context; 21import android.content.Intent; 22import android.os.Handler; 23import android.util.ArraySet; 24import android.widget.Toast; 25 26import com.android.systemui.R; 27import com.android.systemui.recents.events.EventBus; 28import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent; 29import com.android.systemui.recents.misc.SystemServicesProxy; 30import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; 31import com.android.systemui.stackdivider.events.StartedDragingEvent; 32import com.android.systemui.stackdivider.events.StoppedDragingEvent; 33 34/** 35 * Controller that decides when to show the {@link ForcedResizableInfoActivity}. 36 */ 37public class ForcedResizableInfoActivityController { 38 39 private static final String SELF_PACKAGE_NAME = "com.android.systemui"; 40 41 private static final int TIMEOUT = 1000; 42 private final Context mContext; 43 private final Handler mHandler = new Handler(); 44 private final ArraySet<Integer> mPendingTaskIds = new ArraySet<>(); 45 private final ArraySet<String> mPackagesShownInSession = new ArraySet<>(); 46 private boolean mDividerDraging; 47 48 private final Runnable mTimeoutRunnable = new Runnable() { 49 @Override 50 public void run() { 51 showPending(); 52 } 53 }; 54 55 public ForcedResizableInfoActivityController(Context context) { 56 mContext = context; 57 EventBus.getDefault().register(this); 58 SystemServicesProxy.getInstance(context).registerTaskStackListener( 59 new TaskStackListener() { 60 @Override 61 public void onActivityForcedResizable(String packageName, int taskId) { 62 activityForcedResizable(packageName, taskId); 63 } 64 65 @Override 66 public void onActivityDismissingDockedStack() { 67 activityDismissingDockedStack(); 68 } 69 }); 70 } 71 72 public void notifyDockedStackExistsChanged(boolean exists) { 73 if (!exists) { 74 mPackagesShownInSession.clear(); 75 } 76 } 77 78 public final void onBusEvent(AppTransitionFinishedEvent event) { 79 if (!mDividerDraging) { 80 showPending(); 81 } 82 } 83 84 public final void onBusEvent(StartedDragingEvent event) { 85 mDividerDraging = true; 86 mHandler.removeCallbacks(mTimeoutRunnable); 87 } 88 89 public final void onBusEvent(StoppedDragingEvent event) { 90 mDividerDraging = false; 91 showPending(); 92 } 93 94 private void activityForcedResizable(String packageName, int taskId) { 95 if (debounce(packageName)) { 96 return; 97 } 98 mPendingTaskIds.add(taskId); 99 postTimeout(); 100 } 101 102 private void activityDismissingDockedStack() { 103 Toast toast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, 104 Toast.LENGTH_SHORT); 105 toast.show(); 106 } 107 108 private void showPending() { 109 mHandler.removeCallbacks(mTimeoutRunnable); 110 for (int i = mPendingTaskIds.size() - 1; i >= 0; i--) { 111 Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class); 112 ActivityOptions options = ActivityOptions.makeBasic(); 113 options.setLaunchTaskId(mPendingTaskIds.valueAt(i)); 114 options.setTaskOverlay(true); 115 mContext.startActivity(intent, options.toBundle()); 116 } 117 mPendingTaskIds.clear(); 118 } 119 120 private void postTimeout() { 121 mHandler.removeCallbacks(mTimeoutRunnable); 122 mHandler.postDelayed(mTimeoutRunnable, TIMEOUT); 123 } 124 125 private boolean debounce(String packageName) { 126 if (packageName == null) { 127 return false; 128 } 129 130 // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that 131 // triggers another notification. So ignore our own activity. 132 if (SELF_PACKAGE_NAME.equals(packageName)) { 133 return true; 134 } 135 boolean debounce = mPackagesShownInSession.contains(packageName); 136 mPackagesShownInSession.add(packageName); 137 return debounce; 138 } 139} 140