blob: 0f7647dbfd8bb44e921a58581be5258cb97e77e3 [file] [log] [blame]
package com.android.systemui.pip.phone;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.IWindowManager;
import java.util.ArrayList;
public class PipMenuActivityController {
private static final String TAG = "PipMenuActivityController";
public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
public static final String EXTRA_ACTIONS = "actions";
public static final int MESSAGE_MENU_VISIBILITY_CHANGED = 100;
public static final int MESSAGE_EXPAND_PIP = 101;
public static final int MESSAGE_MINIMIZE_PIP = 102;
public static final int MESSAGE_DISMISS_PIP = 103;
public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
/**
* A listener interface to receive notification on changes in PIP.
*/
public interface Listener {
/**
* Called when the PIP menu visibility changes.
*/
void onPipMenuVisibilityChanged(boolean visible);
/**
* Called when the PIP requested to be expanded.
*/
void onPipExpand();
/**
* Called when the PIP requested to be minimized.
*/
void onPipMinimize();
/**
* Called when the PIP requested to be expanded.
*/
void onPipDismiss();
}
private Context mContext;
private IActivityManager mActivityManager;
private IWindowManager mWindowManager;
private ArrayList<Listener> mListeners = new ArrayList<>();
private ParceledListSlice mActions;
private Messenger mToActivityMessenger;
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_MENU_VISIBILITY_CHANGED: {
boolean visible = msg.arg1 > 0;
mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible));
break;
}
case MESSAGE_EXPAND_PIP: {
mListeners.forEach(l -> l.onPipExpand());
// Preemptively mark the menu as invisible once we expand the PiP
mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
break;
}
case MESSAGE_MINIMIZE_PIP: {
mListeners.forEach(l -> l.onPipMinimize());
break;
}
case MESSAGE_DISMISS_PIP: {
mListeners.forEach(l -> l.onPipDismiss());
// Preemptively mark the menu as invisible once we dismiss the PiP
mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
break;
}
case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
mToActivityMessenger = msg.replyTo;
// Mark the menu as invisible once the activity finishes as well
if (mToActivityMessenger == null) {
mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
}
break;
}
}
}
});
public PipMenuActivityController(Context context, IActivityManager activityManager,
IWindowManager windowManager) {
mContext = context;
mActivityManager = activityManager;
mWindowManager = windowManager;
}
/**
* Adds a new menu activity listener.
*/
public void addListener(Listener listener) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}
/**
* Shows the menu activity.
*/
public void showMenu() {
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
try {
mToActivityMessenger.send(m);
} catch (RemoteException e) {
Log.e(TAG, "Could not notify menu to show", e);
}
} else {
// Start the menu activity on the top task of the pinned stack
try {
StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
pinnedStackInfo.taskIds.length > 0) {
Intent intent = new Intent(mContext, PipMenuActivity.class);
intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
intent.putExtra(EXTRA_ACTIONS, mActions);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
options.setLaunchTaskId(
pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
options.setTaskOverlay(true, true /* canResume */);
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
} else {
Log.e(TAG, "No PIP tasks found");
}
} catch (RemoteException e) {
Log.e(TAG, "Error showing PIP menu activity", e);
}
}
}
/**
* Hides the menu activity.
*/
public void hideMenu() {
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
try {
mToActivityMessenger.send(m);
} catch (RemoteException e) {
Log.e(TAG, "Could not notify menu to hide", e);
}
}
}
/**
* Sets the {@param actions} associated with the PiP.
*/
public void setActions(ParceledListSlice actions) {
mActions = actions;
if (mToActivityMessenger != null) {
Message m = Message.obtain();
m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
m.obj = actions;
try {
mToActivityMessenger.send(m);
} catch (RemoteException e) {
Log.e(TAG, "Could not notify menu activity to update actions", e);
}
}
}
}