QuickCaptureInputConsumer -> OverscrollInputConsumer + plugin

Test: Implemented plugin interface in Compose studiow build in
google_experimental, verified plugin shows up appropriately in
Launcher's home settings screen, verified gesture works if Compose
plugin enabled, and doesn't work if Compose plugin disabled.
Bug: n/a

Change-Id: Ica24ee8fe814ee02a1497a1bfbe7c7a24489b71e
This commit is contained in:
James O'Leary 2019-10-15 17:39:03 -04:00
parent d78d80beca
commit 9e57e74005
5 changed files with 99 additions and 71 deletions

View File

@ -35,6 +35,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
@ -49,19 +50,18 @@ import android.view.InputEvent;
import android.view.MotionEvent;
import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
@ -70,12 +70,14 @@ import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer;
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
import com.android.quickstep.inputconsumers.QuickCaptureInputConsumer;
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@ -113,7 +115,7 @@ class ArgList extends LinkedList<String> {
*/
@TargetApi(Build.VERSION_CODES.Q)
public class TouchInteractionService extends Service implements
NavigationModeChangeListener {
NavigationModeChangeListener, PluginListener<OverscrollPlugin> {
private static final String TAG = "TouchInteractionService";
@ -122,6 +124,8 @@ public class TouchInteractionService extends Service implements
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
private int mBackGestureNotificationCounter = -1;
@Nullable
private OverscrollPlugin mOverscrollPlugin;
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@ -280,6 +284,9 @@ public class TouchInteractionService extends Service implements
onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this));
sConnected = true;
PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this,
OverscrollPlugin.class, false /* allowMultiple */);
}
private void disposeEventHandlers() {
@ -400,6 +407,9 @@ public class TouchInteractionService extends Service implements
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS destroyed");
}
PluginManagerWrapper.INSTANCE.get(getBaseContext()).removePluginListener(this);
sIsInitialized = false;
if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
@ -489,10 +499,10 @@ public class TouchInteractionService extends Service implements
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
}
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
// Put the Compose gesture as higher priority than the Assistant or base gestures
base = new QuickCaptureInputConsumer(this, newGestureState, base,
mInputMonitorCompat);
if (mOverscrollPlugin != null) {
// Put the overscroll gesture as higher priority than the Assistant or base gestures
base = new OverscrollInputConsumer(this, newGestureState, base, mInputMonitorCompat,
mOverscrollPlugin);
}
if (mDeviceState.isScreenPinningActive()) {
@ -531,9 +541,9 @@ public class TouchInteractionService extends Service implements
() -> mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT));
if (!ActivityManagerWrapper.isHomeTask(runningTaskInfo)) {
final ComponentName homeComponent =
mOverviewComponentObserver.getHomeIntent().getComponent();
mOverviewComponentObserver.getHomeIntent().getComponent();
forceOverviewInputConsumer =
runningTaskInfo.baseIntent.getComponent(). equals(homeComponent);
runningTaskInfo.baseIntent.getComponent().equals(homeComponent);
}
}
@ -763,4 +773,14 @@ public class TouchInteractionService extends Service implements
UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
.startRecentsActivity(intent, null, listener, null, null));
}
@Override
public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) {
mOverscrollPlugin = overscrollPlugin;
}
@Override
public void onPluginDisconnected(OverscrollPlugin overscrollPlugin) {
mOverscrollPlugin = null;
}
}

View File

@ -24,39 +24,28 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Utilities.squaredHypot;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.shared.system.InputMonitorCompat;
/**
* Input consumer for handling events to launch quick capture from launcher
* Input consumer for handling events to pass to an {@code OverscrollPlugin}.
*
* @param <T> Draggable activity subclass used by RecentsView
*/
public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
extends DelegateInputConsumer {
public class OverscrollInputConsumer<T extends BaseDraggingActivity> extends DelegateInputConsumer {
private static final String TAG = "QuickCaptureInputConsumer";
private static final String QUICK_CAPTURE_PACKAGE = "com.google.auxe.compose";
private static final String QUICK_CAPTURE_PACKAGE_DEV = "com.google.auxe.compose.debug";
private static final String EXTRA_DEVICE_STATE = "deviceState";
private static final String DEVICE_STATE_LOCKED = "Locked";
private static final String DEVICE_STATE_LAUNCHER = "Launcher";
private static final String DEVICE_STATE_APP = "App";
private static final String DEVICE_STATE_UNKNOWN = "Unknown";
private static final String TAG = "OverscrollInputConsumer";
private static final int ANGLE_THRESHOLD = 35; // Degrees
@ -71,14 +60,16 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
private final Context mContext;
private final GestureState mGestureState;
@Nullable private final OverscrollPlugin mPlugin;
private RecentsView mRecentsView;
public QuickCaptureInputConsumer(Context context, GestureState gestureState,
InputConsumer delegate, InputMonitorCompat inputMonitor) {
public OverscrollInputConsumer(Context context, GestureState gestureState,
InputConsumer delegate, InputMonitorCompat inputMonitor, OverscrollPlugin plugin) {
super(delegate, inputMonitor);
mContext = context;
mGestureState = gestureState;
mPlugin = plugin;
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
mSquaredSlop = slop * slop;
@ -89,7 +80,7 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
@Override
public int getType() {
return TYPE_QUICK_CAPTURE | mDelegate.getType();
return TYPE_OVERSCROLL | mDelegate.getType();
}
private boolean onActivityInit(Boolean alreadyOnHome) {
@ -149,7 +140,7 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
mPassedSlop = true;
mStartDragPos.set(mLastPos.x, mLastPos.y);
if (isValidQuickCaptureGesture()) {
if (isOverscrolled()) {
setActive(ev);
} else {
mState = STATE_DELEGATE_ACTIVE;
@ -161,8 +152,8 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
}
case ACTION_CANCEL:
case ACTION_UP:
if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop) {
startQuickCapture();
if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop && mPlugin != null) {
mPlugin.onOverscroll(getDeviceState());
}
mPassedSlop = false;
@ -175,7 +166,7 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
}
}
private boolean isValidQuickCaptureGesture() {
private boolean isOverscrolled() {
// Make sure there isn't an app to quick switch to on our right
boolean atRightMostApp = (mRecentsView == null || mRecentsView.getRunningTaskIndex() <= 0);
@ -187,37 +178,19 @@ public class QuickCaptureInputConsumer<T extends BaseDraggingActivity>
return atRightMostApp && angleInBounds;
}
private void startQuickCapture() {
// Inspect our delegate's type to figure out where the user invoked Compose
String deviceState = DEVICE_STATE_UNKNOWN;
private String getDeviceState() {
String deviceState = OverscrollPlugin.DEVICE_STATE_UNKNOWN;
int consumerType = mDelegate.getType();
if (((consumerType & InputConsumer.TYPE_OVERVIEW) > 0)
|| ((consumerType & InputConsumer.TYPE_OVERVIEW_WITHOUT_FOCUS)) > 0) {
deviceState = DEVICE_STATE_LAUNCHER;
deviceState = OverscrollPlugin.DEVICE_STATE_LAUNCHER;
} else if ((consumerType & InputConsumer.TYPE_OTHER_ACTIVITY) > 0) {
deviceState = DEVICE_STATE_APP;
deviceState = OverscrollPlugin.DEVICE_STATE_APP;
} else if (((consumerType & InputConsumer.TYPE_RESET_GESTURE) > 0)
|| ((consumerType & InputConsumer.TYPE_DEVICE_LOCKED) > 0)) {
deviceState = DEVICE_STATE_LOCKED;
deviceState = OverscrollPlugin.DEVICE_STATE_LOCKED;
}
// Then launch the app
PackageManager pm = mContext.getPackageManager();
Intent qcIntent = pm.getLaunchIntentForPackage(QUICK_CAPTURE_PACKAGE);
if (qcIntent == null) {
// If we couldn't find the regular app, try the dev version
qcIntent = pm.getLaunchIntentForPackage(QUICK_CAPTURE_PACKAGE_DEV);
}
if (qcIntent != null) {
qcIntent.putExtra(EXTRA_DEVICE_STATE, deviceState);
Bundle options = ActivityOptions.makeCustomAnimation(mContext, R.anim.slide_in_right,
0).toBundle();
mContext.startActivity(qcIntent, options);
}
return deviceState;
}
}

View File

@ -33,7 +33,7 @@ public interface InputConsumer {
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
int TYPE_QUICK_CAPTURE = 1 << 9;
int TYPE_OVERSCROLL = 1 << 9;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@ -45,7 +45,7 @@ public interface InputConsumer {
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
"TYPE_QUICK_CAPTURE", // 9
"TYPE_OVERSCROLL", // 9
};
InputConsumer NO_OP = () -> TYPE_NO_OP;

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate
android:duration="@android:integer/config_shortAnimTime"
android:fromXDelta="100%"
android:toXDelta="0%"
/>
</set>

View File

@ -0,0 +1,44 @@
/*
* 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.systemui.plugins;
import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
* Implement this interface to receive a callback when the user swipes right
* to left on the gesture area. It won't fire if the user has quick switched to a previous app
* (swiped right) and the current app isn't yet the active one (i.e., if swiping left would take
* the user to a more recent app).
*/
@ProvidesInterface(action = com.android.systemui.plugins.OverscrollPlugin.ACTION,
version = com.android.systemui.plugins.OverlayPlugin.VERSION)
public interface OverscrollPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_LAUNCHER_OVERSCROLL";
int VERSION = 1;
String DEVICE_STATE_LOCKED = "Locked";
String DEVICE_STATE_LAUNCHER = "Launcher";
String DEVICE_STATE_APP = "App";
String DEVICE_STATE_UNKNOWN = "Unknown";
/**
* Called when the user completed a right to left swipe in the gesture area.
*
* @param deviceState One of the DEVICE_STATE_* constants.
*/
void onOverscroll(String deviceState);
}