blob: 1f332c4ddacf494189e3db3ac078ffaed9ced46d [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.pip.IPipAnimationListener;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import com.android.wm.shell.transition.IShellTransitions;
/**
* Holds the reference to SystemUI.
*/
public class SystemUiProxy implements ISystemUiProxy,
SysUINavigationMode.NavigationModeChangeListener {
private static final String TAG = SystemUiProxy.class.getSimpleName();
public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
new MainThreadInitializedObject<>(SystemUiProxy::new);
private ISystemUiProxy mSystemUiProxy;
private IPip mPip;
private ISplitScreen mSplitScreen;
private IOneHanded mOneHanded;
private IShellTransitions mShellTransitions;
private IStartingWindow mStartingWindow;
private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
MAIN_EXECUTOR.execute(() -> clearProxy());
};
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
private boolean mLastShelfVisible;
private float mLastNavButtonAlpha;
private boolean mLastNavButtonAnimate;
private boolean mHasNavButtonAlphaBeenSet = false;
// TODO(141886704): Find a way to remove this
private int mLastSystemUiStateFlags;
public SystemUiProxy(Context context) {
SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
}
@Override
public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
// Whenever the nav mode changes, force reset the nav button alpha
setNavBarButtonAlpha(1f, false);
}
@Override
public void onBackPressed() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onBackPressed();
} catch (RemoteException e) {
Log.w(TAG, "Failed call onBackPressed", e);
}
}
}
@Override
public IBinder asBinder() {
// Do nothing
return null;
}
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
IOneHanded oneHanded, IShellTransitions shellTransitions,
IStartingWindow startingWindow) {
unlinkToDeath();
mSystemUiProxy = proxy;
mPip = pip;
mSplitScreen = splitScreen;
mOneHanded = oneHanded;
mShellTransitions = shellTransitions;
mStartingWindow = startingWindow;
linkToDeath();
}
public void clearProxy() {
setProxy(null, null, null, null, null, null);
}
// TODO(141886704): Find a way to remove this
public void setLastSystemUiStateFlags(int stateFlags) {
mLastSystemUiStateFlags = stateFlags;
}
// TODO(141886704): Find a way to remove this
public int getLastSystemUiStateFlags() {
return mLastSystemUiStateFlags;
}
public boolean isActive() {
return mSystemUiProxy != null;
}
private void linkToDeath() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to link sysui proxy death recipient");
}
}
}
private void unlinkToDeath() {
if (mSystemUiProxy != null) {
mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
}
}
@Override
public void startScreenPinning(int taskId) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.startScreenPinning(taskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startScreenPinning", e);
}
}
}
@Override
public void onOverviewShown(boolean fromHome) {
onOverviewShown(fromHome, TAG);
}
public void onOverviewShown(boolean fromHome, String tag) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onOverviewShown(fromHome);
} catch (RemoteException e) {
Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e);
}
}
}
@Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
if (mSystemUiProxy != null) {
try {
return mSystemUiProxy.getNonMinimizedSplitScreenSecondaryBounds();
} catch (RemoteException e) {
Log.w(TAG, "Failed call getNonMinimizedSplitScreenSecondaryBounds", e);
}
}
return null;
}
public float getLastNavButtonAlpha() {
return mLastNavButtonAlpha;
}
@Override
public void setNavBarButtonAlpha(float alpha, boolean animate) {
boolean changed = Float.compare(alpha, mLastNavButtonAlpha) != 0
|| animate != mLastNavButtonAnimate
|| !mHasNavButtonAlphaBeenSet;
if (mSystemUiProxy != null && changed) {
mLastNavButtonAlpha = alpha;
mLastNavButtonAnimate = animate;
mHasNavButtonAlphaBeenSet = true;
try {
mSystemUiProxy.setNavBarButtonAlpha(alpha, animate);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setNavBarButtonAlpha", e);
}
}
}
@Override
public void onStatusBarMotionEvent(MotionEvent event) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onStatusBarMotionEvent(event);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onStatusBarMotionEvent", e);
}
}
}
@Override
public void onAssistantProgress(float progress) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onAssistantProgress(progress);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e);
}
}
}
@Override
public void onAssistantGestureCompletion(float velocity) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onAssistantGestureCompletion(velocity);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onAssistantGestureCompletion", e);
}
}
}
@Override
public void startAssistant(Bundle args) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.startAssistant(args);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startAssistant", e);
}
}
}
@Override
public Bundle monitorGestureInput(String name, int displayId) {
if (mSystemUiProxy != null) {
try {
return mSystemUiProxy.monitorGestureInput(name, displayId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call monitorGestureInput: " + name, e);
}
}
return null;
}
@Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.notifyAccessibilityButtonClicked(displayId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e);
}
}
}
@Override
public void notifyAccessibilityButtonLongClicked() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.notifyAccessibilityButtonLongClicked();
} catch (RemoteException e) {
Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e);
}
}
}
@Override
public void stopScreenPinning() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.stopScreenPinning();
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopScreenPinning", e);
}
}
}
@Override
public void handleImageAsScreenshot(Bitmap bitmap, Rect rect, Insets insets, int i) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.handleImageAsScreenshot(bitmap, rect, insets, i);
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageAsScreenshot", e);
}
}
}
@Override
public void setSplitScreenMinimized(boolean minimized) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.setSplitScreenMinimized(minimized);
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopScreenPinning", e);
}
}
}
/**
* Notifies that swipe-to-home action is finished.
*/
@Override
public void notifySwipeToHomeFinished() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.notifySwipeToHomeFinished();
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationType", e);
}
}
}
@Override
public void onQuickSwitchToNewTask(int rotation) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.onQuickSwitchToNewTask(rotation);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onQuickSwitchToNewTask with arg: " + rotation, e);
}
}
}
@Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.handleImageBundleAsScreenshot(screenImageBundle, locationInScreen,
visibleInsets, task);
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
}
}
}
@Override
public void expandNotificationPanel() {
if (mSystemUiProxy != null) {
try {
mSystemUiProxy.expandNotificationPanel();
} catch (RemoteException e) {
Log.w(TAG, "Failed call expandNotificationPanel", e);
}
}
}
//
// Pip
//
/**
* Sets the shelf height.
*/
public void setShelfHeight(boolean visible, int shelfHeight) {
boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
if (mPip != null && changed) {
mLastShelfVisible = visible;
mLastShelfHeight = shelfHeight;
try {
mPip.setShelfHeight(visible, shelfHeight);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setShelfHeight visible: " + visible
+ " height: " + shelfHeight, e);
}
}
}
/**
* Sets listener to get pinned stack animation callbacks.
*/
public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
if (mPip != null) {
try {
mPip.setPinnedStackAnimationListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
}
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams pictureInPictureParams, int launcherRotation, int shelfHeight) {
if (mPip != null) {
try {
return mPip.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams, launcherRotation, shelfHeight);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startSwipePipToHome", e);
}
}
return null;
}
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
if (mPip != null) {
try {
mPip.stopSwipePipToHome(componentName, destinationBounds);
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopSwipePipToHome");
}
}
}
//
// Splitscreen
//
public void registerSplitScreenListener(ISplitScreenListener listener) {
if (mSplitScreen != null) {
try {
mSplitScreen.registerSplitScreenListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
}
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
if (mSplitScreen != null) {
try {
mSplitScreen.unregisterSplitScreenListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
}
public void setSideStageVisibility(boolean visible) {
if (mSplitScreen != null) {
try {
mSplitScreen.setSideStageVisibility(visible);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setSideStageVisibility");
}
}
}
public void exitSplitScreen() {
if (mSplitScreen != null) {
try {
mSplitScreen.exitSplitScreen();
} catch (RemoteException e) {
Log.w(TAG, "Failed call exitSplitScreen");
}
}
}
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
if (mSplitScreen != null) {
try {
mSplitScreen.exitSplitScreenOnHide(exitSplitScreenOnHide);
} catch (RemoteException e) {
Log.w(TAG, "Failed call exitSplitScreen");
}
}
}
public void startTask(int taskId, int stage, int position, Bundle options) {
if (mSplitScreen != null) {
try {
mSplitScreen.startTask(taskId, stage, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTask");
}
}
}
public void startShortcut(String packageName, String shortcutId, int stage, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
try {
mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options,
user);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startShortcut");
}
}
}
public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
Bundle options) {
if (mSplitScreen != null) {
try {
mSplitScreen.startIntent(intent, fillInIntent, stage, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntent");
}
}
}
public void removeFromSideStage(int taskId) {
if (mSplitScreen != null) {
try {
mSplitScreen.removeFromSideStage(taskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call removeFromSideStage");
}
}
}
//
// One handed
//
public void startOneHandedMode() {
if (mOneHanded != null) {
try {
mOneHanded.startOneHanded();
} catch (RemoteException e) {
Log.w(TAG, "Failed call startOneHandedMode", e);
}
}
}
public void stopOneHandedMode() {
if (mOneHanded != null) {
try {
mOneHanded.stopOneHanded();
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopOneHandedMode", e);
}
}
}
//
// Remote transitions
//
public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
if (mShellTransitions != null) {
try {
mShellTransitions.registerRemote(remoteTransition.getFilter(),
remoteTransition.getTransition());
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
}
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
if (mShellTransitions != null) {
try {
mShellTransitions.unregisterRemote(remoteTransition.getTransition());
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
}
//
// Starting window
//
/**
* Sets listener to get callbacks when launching a task.
*/
public void setStartingWindowListener(IStartingWindowListener listener) {
if (mStartingWindow != null) {
try {
mStartingWindow.setStartingWindowListener(listener);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
}
}
}