blob: c828edea78e0e4d713649bd357c1077cf3a583ca [file] [log] [blame]
Winson73bc1592016-10-18 18:47:43 -07001/*
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.pip.phone;
18
Winson Chung3535df22017-01-17 18:43:39 -080019import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
Winson Chunga29eb982016-12-14 12:01:27 -080020import static android.view.Display.DEFAULT_DISPLAY;
21
Sudheer Shankadc589ac2016-11-10 15:30:17 -080022import android.app.ActivityManager;
Winson Chung3535df22017-01-17 18:43:39 -080023import android.app.ActivityManager.StackInfo;
24import android.app.ActivityOptions;
Winson73bc1592016-10-18 18:47:43 -070025import android.app.IActivityManager;
Winson Chung3535df22017-01-17 18:43:39 -080026import android.content.ComponentName;
Winson73bc1592016-10-18 18:47:43 -070027import android.content.Context;
Winson Chung3535df22017-01-17 18:43:39 -080028import android.content.Intent;
Winson Chunga29eb982016-12-14 12:01:27 -080029import android.content.pm.ParceledListSlice;
30import android.os.Handler;
31import android.os.RemoteException;
Winson Chung3535df22017-01-17 18:43:39 -080032import android.os.UserHandle;
Winson Chunga29eb982016-12-14 12:01:27 -080033import android.util.Log;
34import android.view.IPinnedStackController;
35import android.view.IPinnedStackListener;
Winson73bc1592016-10-18 18:47:43 -070036import android.view.IWindowManager;
37import android.view.WindowManagerGlobal;
38
Winson Chung929d4f72017-01-13 10:21:33 -080039import com.android.systemui.recents.misc.SystemServicesProxy;
40import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
41
Winson73bc1592016-10-18 18:47:43 -070042/**
43 * Manages the picture-in-picture (PIP) UI and states for Phones.
44 */
45public class PipManager {
46 private static final String TAG = "PipManager";
47
48 private static PipManager sPipController;
49
50 private Context mContext;
51 private IActivityManager mActivityManager;
52 private IWindowManager mWindowManager;
Winson Chunga29eb982016-12-14 12:01:27 -080053 private Handler mHandler = new Handler();
54
55 private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
Winson73bc1592016-10-18 18:47:43 -070056
Winson Chung15504af2016-11-02 18:11:36 -070057 private PipMenuActivityController mMenuController;
Winson73bc1592016-10-18 18:47:43 -070058 private PipTouchHandler mTouchHandler;
59
Winson Chunga29eb982016-12-14 12:01:27 -080060 /**
Winson Chung929d4f72017-01-13 10:21:33 -080061 * Handler for system task stack changes.
62 */
63 TaskStackListener mTaskStackListener = new TaskStackListener() {
64 @Override
65 public void onActivityPinned() {
Winson Chung3535df22017-01-17 18:43:39 -080066 if (!checkCurrentUserId(false /* debug */)) {
67 return;
68 }
Winson Chung929d4f72017-01-13 10:21:33 -080069 mTouchHandler.onActivityPinned();
70 }
71
72 @Override
73 public void onPinnedStackAnimationEnded() {
74 // TODO(winsonc): Disable touch interaction with the PiP until the animation ends
75 }
76
77 @Override
Winson Chung3535df22017-01-17 18:43:39 -080078 public void onPinnedActivityRestartAttempt(ComponentName sourceComponent) {
79 if (!checkCurrentUserId(false /* debug */)) {
80 return;
81 }
82
83 // Expand the activity back to fullscreen only if it was attempted to be restarted from
84 // another package than the top activity in the stack
85 boolean expandPipToFullscreen = true;
86 if (sourceComponent != null) {
87 try {
88 StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
89 if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
90 pinnedStackInfo.taskIds.length > 0) {
91 expandPipToFullscreen =
92 !pinnedStackInfo.topActivity.getPackageName().equals(
93 sourceComponent.getPackageName());
94 }
95 } catch (RemoteException e) {
96 Log.w(TAG, "Unable to get pinned stack.");
97 }
98 }
99 if (expandPipToFullscreen) {
100 mTouchHandler.expandPinnedStackToFullscreen();
101 } else {
102 Log.w(TAG, "Can not expand PiP to fullscreen via intent from the same package.");
103 }
Winson Chung929d4f72017-01-13 10:21:33 -0800104 }
105 };
106
107 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800108 * Handler for messages from the PIP controller.
109 */
110 private class PinnedStackListener extends IPinnedStackListener.Stub {
111
112 @Override
113 public void onListenerRegistered(IPinnedStackController controller) {
114 mHandler.post(() -> {
115 mTouchHandler.setPinnedStackController(controller);
116 });
117 }
118
119 @Override
120 public void onBoundsChanged(boolean adjustedForIme) {
121 // Do nothing
122 }
123
124 @Override
125 public void onActionsChanged(ParceledListSlice actions) {
126 mHandler.post(() -> {
127 mMenuController.setActions(actions);
128 });
129 }
130
131 @Override
132 public void onMinimizedStateChanged(boolean isMinimized) {
133 mHandler.post(() -> {
134 mTouchHandler.onMinimizedStateChanged(isMinimized);
135 });
136 }
137
138 @Override
139 public void onSnapToEdgeStateChanged(boolean isSnapToEdge) {
140 mHandler.post(() -> {
141 mTouchHandler.onSnapToEdgeStateChanged(isSnapToEdge);
142 });
143 }
144 }
145
Winson73bc1592016-10-18 18:47:43 -0700146 private PipManager() {}
147
148 /**
149 * Initializes {@link PipManager}.
150 */
151 public void initialize(Context context) {
152 mContext = context;
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800153 mActivityManager = ActivityManager.getService();
Winson73bc1592016-10-18 18:47:43 -0700154 mWindowManager = WindowManagerGlobal.getWindowManagerService();
155
Winson Chunga29eb982016-12-14 12:01:27 -0800156 try {
157 mWindowManager.registerPinnedStackListener(DEFAULT_DISPLAY, mPinnedStackListener);
158 } catch (RemoteException e) {
159 Log.e(TAG, "Failed to register pinned stack listener", e);
160 }
Winson Chung929d4f72017-01-13 10:21:33 -0800161 SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
Winson Chunga29eb982016-12-14 12:01:27 -0800162
Winson Chung15504af2016-11-02 18:11:36 -0700163 mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager);
164 mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager,
165 mWindowManager);
Winson73bc1592016-10-18 18:47:43 -0700166 }
167
168 /**
169 * Updates the PIP per configuration changed.
170 */
Winson Chung303c6b72016-10-24 17:12:49 -0700171 public void onConfigurationChanged() {
172 mTouchHandler.onConfigurationChanged();
173 }
Winson73bc1592016-10-18 18:47:43 -0700174
175 /**
176 * Gets an instance of {@link PipManager}.
177 */
178 public static PipManager getInstance() {
179 if (sPipController == null) {
180 sPipController = new PipManager();
181 }
182 return sPipController;
183 }
184}